/**
* @copyright 2025 Chris Bunting <cbuntingde@gmail.com>
* @license MIT
*
* Tool handlers for the Memory MCP Server
*/
import {
ListToolsRequestSchema,
CallToolRequestSchema,
McpError,
ErrorCode
} from "@modelcontextprotocol/sdk/types.js";
import { MemoryStore } from "../store/MemoryStore.js";
import { ValidationUtils } from "../utils/Validation.js";
export function setupToolHandlers(server: any, memoryStore: MemoryStore): void {
// List available tools
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
name: "set_short_term_memory",
description: "Store data in short-term memory for a session",
inputSchema: {
type: "object",
properties: {
sessionId: {
type: "string",
description: "Session identifier"
},
key: {
type: "string",
description: "Memory key"
},
value: {
description: "Memory value (any JSON-serializable data)"
},
ttlMinutes: {
type: "number",
description: "Time to live in minutes (default: 30)",
default: 30
}
},
required: ["sessionId", "key", "value"]
}
},
{
name: "get_short_term_memory",
description: "Retrieve data from short-term memory",
inputSchema: {
type: "object",
properties: {
sessionId: {
type: "string",
description: "Session identifier"
},
key: {
type: "string",
description: "Memory key (optional, returns all if not provided)"
}
},
required: ["sessionId"]
}
},
{
name: "set_long_term_memory",
description: "Store user demographics, contact details, or preferences",
inputSchema: {
type: "object",
properties: {
userId: {
type: "string",
description: "User identifier"
},
demographics: {
type: "object",
description: "User demographics (age, location, occupation, etc.)"
},
contact: {
type: "object",
description: "Contact information"
},
preferences: {
type: "object",
description: "User preferences and settings"
}
},
required: ["userId"]
}
},
{
name: "get_long_term_memory",
description: "Retrieve long-term memory for a user",
inputSchema: {
type: "object",
properties: {
userId: {
type: "string",
description: "User identifier"
}
},
required: ["userId"]
}
},
{
name: "add_episodic_memory",
description: "Add a new episodic memory (past experience or event)",
inputSchema: {
type: "object",
properties: {
userId: {
type: "string",
description: "User identifier"
},
sessionId: {
type: "string",
description: "Optional session identifier"
},
event: {
type: "string",
description: "Description of the event"
},
context: {
type: "string",
description: "Context surrounding the event"
},
outcome: {
type: "string",
description: "Outcome or resolution of the event"
},
sentiment: {
type: "string",
enum: ["positive", "negative", "neutral"],
description: "Sentiment of the experience"
},
tags: {
type: "array",
items: { type: "string" },
description: "Tags for categorizing the memory"
}
},
required: ["userId", "event", "context"]
}
},
{
name: "get_episodic_memory",
description: "Retrieve episodic memories for a user",
inputSchema: {
type: "object",
properties: {
userId: {
type: "string",
description: "User identifier"
},
limit: {
type: "number",
description: "Maximum number of memories to return"
}
},
required: ["userId"]
}
},
{
name: "search_episodic_memory",
description: "Search episodic memories by content",
inputSchema: {
type: "object",
properties: {
userId: {
type: "string",
description: "User identifier"
},
query: {
type: "string",
description: "Search query"
},
limit: {
type: "number",
description: "Maximum number of results"
}
},
required: ["userId", "query"]
}
}
]
};
});
// Handle tool calls
server.setRequestHandler(CallToolRequestSchema, async (request: any) => {
switch (request.params.name) {
case "set_short_term_memory": {
const { sessionId, key, value, ttlMinutes = 30 } = request.params.arguments as any;
// Validate inputs
ValidationUtils.validateSessionId(sessionId);
ValidationUtils.validateMemoryKey(key);
ValidationUtils.validateTTLMinutes(ttlMinutes);
memoryStore.setShortTermMemory(sessionId, key, value, ttlMinutes);
return {
content: [{
type: "text",
text: `Stored short-term memory for session ${sessionId}: ${key}`
}]
};
}
case "get_short_term_memory": {
const { sessionId, key } = request.params.arguments as any;
// Validate inputs
ValidationUtils.validateSessionId(sessionId);
if (key !== undefined) {
ValidationUtils.validateMemoryKey(key);
}
const memory = memoryStore.getShortTermMemory(sessionId, key);
return {
content: [{
type: "text",
text: JSON.stringify(memory, null, 2)
}]
};
}
case "set_long_term_memory": {
const { userId, demographics, contact, preferences } = request.params.arguments as any;
// Validate inputs
ValidationUtils.validateUserId(userId);
memoryStore.setLongTermMemory(userId, { demographics, contact, preferences });
return {
content: [{
type: "text",
text: `Updated long-term memory for user ${userId}`
}]
};
}
case "get_long_term_memory": {
const { userId } = request.params.arguments as any;
// Validate inputs
ValidationUtils.validateUserId(userId);
const memory = memoryStore.getLongTermMemory(userId);
return {
content: [{
type: "text",
text: JSON.stringify(memory, null, 2)
}]
};
}
case "add_episodic_memory": {
const memoryData = request.params.arguments as any;
// Validate inputs
ValidationUtils.validateUserId(memoryData.userId);
ValidationUtils.validateEpisodicEvent(memoryData.event);
ValidationUtils.validateEpisodicContext(memoryData.context);
if (memoryData.sessionId !== undefined) {
ValidationUtils.validateSessionId(memoryData.sessionId);
}
if (memoryData.outcome !== undefined) {
ValidationUtils.validateEpisodicOutcome(memoryData.outcome);
}
ValidationUtils.validateSentiment(memoryData.sentiment);
ValidationUtils.validateTags(memoryData.tags);
const id = memoryStore.addEpisodicMemory(memoryData);
return {
content: [{
type: "text",
text: `Added episodic memory with ID: ${id}`
}]
};
}
case "get_episodic_memory": {
const { userId, limit } = request.params.arguments as any;
// Validate inputs
ValidationUtils.validateUserId(userId);
ValidationUtils.validateLimit(limit);
const memories = memoryStore.getEpisodicMemory(userId, limit);
return {
content: [{
type: "text",
text: JSON.stringify(memories, null, 2)
}]
};
}
case "search_episodic_memory": {
const { userId, query, limit } = request.params.arguments as any;
// Validate inputs
ValidationUtils.validateUserId(userId);
ValidationUtils.validateSearchQuery(query);
ValidationUtils.validateLimit(limit);
const memories = memoryStore.searchEpisodicMemory(userId, query, limit);
return {
content: [{
type: "text",
text: JSON.stringify(memories, null, 2)
}]
};
}
default:
throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${request.params.name}`);
}
});
}