Copyright 2025 Chris Bunting cbuntingde@gmail.com
A production-ready Model Context Protocol (MCP) server implementing a robust three-tiered memory architecture designed for vertical AI agents and applications requiring sophisticated context management.
The Memory MCP Server provides a comprehensive, persistent, and session-based memory management system through three specialized and configurable memory types:
- Short-term Memory: Volatile, session-specific context with a configurable Time-To-Live (TTL), ideal for maintaining conversational state or temporary operational data. (Default TTL: 30 minutes)
- Long-term Memory: Persistent storage for user profiles, preferences, demographics, and other stable, long-lived data that defines user characteristics.
- Episodic Memory: A searchable, time-stamped log of events, interactions, and experiences, enriched with sentiment analysis and tagging for advanced context retrieval and pattern recognition.
This architecture enables AI agents to maintain continuity across sessions, personalize interactions based on historical data, and reason over past events to provide more intelligent and context-aware responses.
The project is organized with a clear separation of concerns, promoting maintainability, scalability, and testability.
memory-mcp-server/
├── src/
│ ├── types/ # TypeScript type definitions and interfaces
│ │ └── index.ts
│ ├── store/ # Core memory storage and retrieval logic
│ │ └── MemoryStore.ts
│ ├── handlers/ # MCP protocol handlers (Tools, Resources, Prompts)
│ │ ├── ResourceHandlers.ts
│ │ ├── ToolHandlers.ts
│ │ └── PromptHandlers.ts
│ ├── config/ # Server configuration and settings management
│ │ └── ServerConfig.ts
│ ├── utils/ # Shared utility functions (logging, validation, etc.)
│ │ ├── Logger.ts
│ │ └── Validation.ts
│ └── index.ts # Main server entry point and MCP server setup
├── memory-data/ # Default directory for persistent data storage
│ ├── long-term.json # Stores long-term user profiles and preferences
│ └── episodic.json # Stores episodic event and experience logs
├── test-memory.js # Functional test suite
├── package.json # Project dependencies and scripts
├── tsconfig.json # TypeScript compiler configuration
├── .gitignore # Git ignore rules
├── LICENSE # MIT license file
└── README.md # This file
| Memory Type | Persistence | Primary Use Case | TTL | Storage Mechanism |
|---|---|---|---|---|
| Short-term | In-memory only | Session context, temporary state, conversational flow. | Configurable (default: 30 minutes) | Volatile RAM |
| Long-term | Disk-based (JSON) | User profiles, preferences, demographics, contact info. | Permanent (until explicitly deleted) | memory-data/long-term.json |
| Episodic | Disk-based (JSON) | Event history, experiences, interactions, sentiment tracking. | Permanent (until explicitly deleted) | memory-data/episodic.json |
- Request: An MCP client (e.g., an AI agent) sends a request via a tool, resource, or prompt.
- Handler: The appropriate handler (
ToolHandlers.ts,ResourceHandlers.ts, orPromptHandlers.ts) receives and parses the request. - Validation: Input parameters are validated using
Validation.ts. - Store Interaction: The handler interacts with
MemoryStore.tsto perform CRUD operations on the respective memory tier. - Persistence: For long-term and episodic memories, data is atomically written to JSON files on disk.
- Response: The result is formatted and returned to the MCP client.
- Logging: All operations are logged via
Logger.tsfor monitoring and debugging.
- Node.js: Version 16.0 or higher.
- npm: Version 7.0 or higher (or yarn/pnpm).
- MCP Client: An application or environment that can connect to and utilize MCP servers (e.g., Cline, Claude Desktop).
-
Clone the Repository
git clone https://github.com/cbuntingde/memory-mcp-server.git cd memory-mcp-server -
Install Dependencies
npm install # or yarn install # or pnpm install
-
Build the Project Compile the TypeScript source code into JavaScript.
npm run build
-
Configure Your MCP Client You need to inform your MCP client about the Memory Server. This is typically done by adding a configuration entry to your client's settings file (e.g.,
cline_mcp_settings.jsonfor Cline, orclaude_desktop_config.jsonfor Claude Desktop).Example MCP Configuration:
{ "mcpServers": { "memory-server": { "command": "node", "args": ["./path/to/memory-mcp-server/build/index.js"], "env": { "MEMORY_DATA_DIR": "./custom-memory-data" // Optional: override default data directory }, "settings": { "dataDirectory": "./memory-mcp-server/memory-data", // Optional: can also be set here "defaultTTLMinutes": 30, // Optional: override default short-term TTL "logLevel": "info" // Optional: set logging level (trace, debug, info, warn, error) } } } }Replace
./path/to/memory-mcp-server/build/index.jswith the actual path to the builtindex.jsfile.
The server exposes its functionality through MCP Tools, Resources, and Prompts.
Tools are used for actions that modify or retrieve specific data.
| Tool Name | Description | Required Parameters | Optional Parameters |
|---|---|---|---|
set_short_term_memory |
Stores a key-value pair in a session's short-term memory. | sessionId (string), key (string), value (any JSON-serializable) |
ttlMinutes (number) |
get_short_term_memory |
Retrieves all data for a given session from short-term memory. | sessionId (string) |
- |
set_long_term_memory |
Creates or updates a user's long-term memory profile. | userId (string), data (object) |
- |
get_long_term_memory |
Retrieves a user's long-term memory profile. | userId (string) |
- |
add_episodic_memory |
Adds a new event or experience to a user's episodic memory. | userId (string), event (string) |
context (string), outcome (string), sentiment ('positive', 'negative', 'neutral'), tags (string[]), sessionId (string) |
get_episodic_memory |
Retrieves all episodic memories for a user, optionally sorted. | userId (string) |
sortBy ('timestamp_asc', 'timestamp_desc', 'sentiment'), limit (number) |
search_episodic_memory |
Searches a user's episodic memory by keyword, tag, or sentiment. | userId (string), query (string) |
searchIn ('event', 'context', 'outcome', 'tags'), limit (number) |
Resources provide access to structured data, typically in JSON format.
| Resource URI | Description | Returns |
|---|---|---|
memory://long-term/{userId} |
Fetches the complete long-term memory profile for a specific user. | JSON object representing the user's profile. |
memory://episodic/{userId} |
Fetches all episodic memory entries for a specific user. | JSON array of episodic memory objects. |
Prompts are templates that guide an AI agent to generate responses based on memory data.
| Prompt Name | Description | Required Arguments | Optional Arguments |
|---|---|---|---|
memory_summary |
Generates a comprehensive summary of a user's profile and recent history. | userId (string) |
includeEpisodicCount (number, default: 10) |
personalization_insights |
Extracts key personalization opportunities from a user's long-term and episodic data. | userId (string) |
- |
Here are practical examples demonstrating how to interact with the Memory MCP Server using its tools.
// Store comprehensive user preferences and demographics
await client.callTool({
name: "set_long_term_memory",
arguments: {
userId: "user-abc-123",
data: {
demographics: {
age: 42,
location: "San Francisco, CA",
occupation: "Software Engineer"
},
contact: {
email: "user@example.com",
phone: "+1-555-123-4567" // Note: Ensure compliance with privacy regulations
},
preferences: {
seating: "window seat",
temperature: "cool",
communicationStyle: "concise",
interests: ["technology", "hiking", "photography"]
}
}
}
});
// Retrieve the user's profile
const userProfile = await client.callTool({
name: "get_long_term_memory",
arguments: {
userId: "user-abc-123"
}
});
console.log("User Profile:", userProfile);// Record a positive customer service interaction
await client.callTool({
name: "add_episodic_memory",
arguments: {
userId: "user-abc-123",
sessionId: "session-xyz-789",
event: "Customer inquired about premium features.",
context: "User was on the pricing page and initiated a support chat.",
outcome: "Explained premium benefits, user seemed interested.",
sentiment: "positive",
tags: ["support", "pricing", "premium-features"]
}
});
// Search for past interactions related to "pricing"
const pricingInteractions = await client.callTool({
name: "search_episodic_memory",
arguments: {
userId: "user-abc-123",
query: "pricing",
searchIn: "event",
limit: 5
}
});
console.log("Pricing-related interactions:", pricingInteractions);// Store the current state of a user's shopping cart
await client.callTool({
name: "set_short_term_memory",
arguments: {
sessionId: "session-xyz-789",
key: "shopping_cart",
value: {
items: [
{ productId: "prod-001", name: "Memory MCP Server License", quantity: 1, price: 99.99 }
],
total: 99.99,
currency: "USD"
},
ttlMinutes: 60 // Extend TTL for this session
}
});
// Retrieve the cart later in the session
const currentCart = await client.callTool({
name: "get_short_term_memory",
arguments: {
sessionId: "session-xyz-789"
}
});
console.log("Current Shopping Cart:", currentCart?.shopping_cart);// Ask the AI agent to generate a summary of the user
const summaryPrompt = await client.getPrompt({
name: "memory_summary",
arguments: {
userId: "user-abc-123",
includeEpisodicCount: 15
}
});
// The 'summaryPrompt' would then be fed to the LLM to generate a textual summary.
console.log("Prompt for LLM:", summaryPrompt.messages[0].content.text);Data stored in long-term.json follows this structure:
{
"userId": {
"demographics": {
"age": "number | null",
"location": "string | null",
"occupation": "string | null"
},
"contact": {
"email": "string | null",
"phone": "string | null"
},
"preferences": {
"seating": "string | null",
"temperature": "string | null",
"communicationStyle": "string | null",
"interests": "string[] | null"
},
"metadata": {
"createdAt": "timestamp (ISO 8601 string)",
"lastUpdated": "timestamp (ISO 8601 string)"
}
}
}Data stored in episodic.json follows this structure:
{
"id": "episodic_{timestamp}_{randomId}",
"userId": "string",
"sessionId": "string | null",
"event": "string",
"context": "string | null",
"outcome": "string | null",
"sentiment": "positive | negative | neutral | null",
"tags": "string[]",
"timestamp": "number (Unix epoch in ms)",
"metadata": {
"createdAt": "timestamp (ISO 8601 string)"
}
}# Install dependencies
npm install
# Build the project from TypeScript to JavaScript in /build
npm run build
# Build in watch mode for development (auto-recompile on changes)
npm run watch
# Run the functional test suite (requires build first)
npm run test
# Run the MCP Inspector for debugging MCP server interactions
npm run inspectorThe project includes a functional test suite located in test-memory.js. These tests verify the core functionality of all memory operations.
To run the tests:
- Ensure the project is built:
npm run build - Execute the test script:
npm run testornode test-memory.js
The tests will create and use a temporary data directory to avoid interfering with production data.
- TypeScript: All code is written in TypeScript for type safety and better developer experience.
- ESLint & Prettier: Configured for consistent code style and quality (ensure you have editor plugins or run linting manually).
- Logging: Comprehensive logging is implemented using
Logger.ts. Log levels can be configured via environment variables or MCP settings. - Validation: All external inputs are rigorously validated using
Validation.tsto prevent errors and ensure data integrity.
- Memory Operations (Short-term): Typically < 5ms. Operates entirely in memory.
- Disk Operations (Long-term/Episodic): Typically < 50ms on modern SSDs. File I/O is atomic and synchronous to ensure data consistency.
- Search Operations (Episodic): Performance scales linearly with the number of records. < 100ms for datasets up to 10,000 records. For larger datasets, consider integrating a dedicated search engine (e.g., Lunr.js, ElasticSearch).
- Memory Usage: Primarily determined by the size of in-memory short-term data and the active working set of long-term/episodic data loaded from disk.
- Input Validation: All parameters passed to tools and resources are strictly validated for type, format, and content to prevent injection attacks and malformed data.
- Data Sanitization: While the server itself doesn't render HTML, data is stored in a way that assumes it might be used in contexts where escaping is necessary.
- File System Security: The server writes to a specific, configurable directory. Ensure this directory has appropriate permissions to prevent unauthorized access or modification.
- No External Dependencies: The server has no network dependencies, reducing the attack surface.
- Local Data Storage: All data is stored locally on the file system. You are responsible for securing the host machine and the data directory.
- Atomic Writes: Disk writes for long-term and episodic memories are performed atomically (write to a temporary file, then rename) to prevent data corruption if the process is interrupted.
- Graceful Degradation: If the data directory becomes unwritable, the server will log errors but continue to function for short-term memory operations.
- Automatic Cleanup: Short-term memory entries are automatically purged when their TTL expires, preventing memory leaks.
- Error Handling: Comprehensive error handling is implemented throughout, with clear error messages returned to the MCP client where appropriate.
- Structured Logging: All operations are logged with relevant context (user ID, session ID, operation type, duration) in a structured format (JSON), making it easy to parse and analyze logs.
- Log Levels: Configurable log levels (
trace,debug,info,warn,error) allow for verbose debugging during development and minimal logging in production. - Health Checks: The server responds to standard MCP pings, allowing for basic health monitoring.
- Data Integrity Checks: On startup, the server can optionally verify the basic structure of existing data files (planned for future versions).
Server fails to start or MCP client cannot connect.
- Verify Node.js Version: Ensure you are using Node.js 16.0 or higher (
node -v). - Check Build Step: Run
npm run buildto ensure the TypeScript code is compiled to/build/index.js. - Check File Path: In your MCP client configuration, double-check the path to
build/index.js. It should be an absolute path or a path relative to where the MCP client is run. - Examine Logs: Check the console output from the MCP client or the terminal where you might be running the server directly for error messages. Enable debug logging:
DEBUG=memory-server:* node build/index.js.
Data is not persisting across server restarts.
- Data Directory Permissions: Ensure the
memory-data/directory (or your customdataDirectory) exists and is writable by the process running the server. - Disk Space: Verify that there is sufficient disk space available on the volume where the data directory is located.
- Configuration: Confirm that the
dataDirectorysetting in your MCP configuration is pointing to the correct and intended location.
"Memory not found" errors.
- ID Validation: Double-check the
userIdorsessionIdfor typos or incorrect formatting. - TTL Expiration: For short-term memory, confirm that the session has not expired (i.e., its TTL has not been exceeded).
- Operation Sequencing: Ensure that data was written to memory before attempting to read it. Check logs for previous write operations.
For detailed debugging output, you can run the server with the DEBUG environment variable set:
# From the project directory
DEBUG=memory-server:* node build/index.jsThis will enable verbose logging for all components of the memory server, providing insights into internal operations, data flow, and potential issues.
Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
Please ensure all code adheres to the project's coding standards and includes appropriate tests for new functionality.
This project is licensed under the MIT License - see the LICENSE file for details.
- Issues & Bug Reports: Please use the GitHub Issues page to report bugs or request features.
Production Implementation: This server is built with a focus on robustness, security, and operational reliability, making it suitable for integration into production AI systems and applications.