@memoryrelay/mcp-server 0.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/config.ts","../src/logger.ts","../src/server.ts","../src/client.ts","../src/index.ts"],"sourcesContent":["import { z } from 'zod';\n\n/**\n * Configuration schema with security validation\n */\nexport const configSchema = z.object({\n apiKey: z.string()\n .startsWith('mem_', { message: 'API key must start with \"mem_\"' })\n .min(20, { message: 'API key appears to be invalid (too short)' }),\n apiUrl: z.string()\n .url({ message: 'API URL must be a valid URL' })\n .default('https://api.memoryrelay.net'),\n agentId: z.string()\n .optional()\n .describe('Agent identifier - auto-detected if not provided'),\n timeout: z.number()\n .positive({ message: 'Timeout must be positive' })\n .default(30000),\n logLevel: z.enum(['debug', 'info', 'warn', 'error'])\n .default('info'),\n});\n\nexport type Config = z.infer<typeof configSchema>;\n\n/**\n * Load and validate configuration from environment variables\n */\nexport function loadConfig(): Config {\n try {\n const config = configSchema.parse({\n apiKey: process.env.MEMORYRELAY_API_KEY,\n apiUrl: process.env.MEMORYRELAY_API_URL,\n agentId: process.env.MEMORYRELAY_AGENT_ID,\n timeout: process.env.MEMORYRELAY_TIMEOUT \n ? parseInt(process.env.MEMORYRELAY_TIMEOUT, 10) \n : undefined,\n logLevel: process.env.MEMORYRELAY_LOG_LEVEL,\n });\n\n return config;\n } catch (error) {\n if (error instanceof z.ZodError) {\n const issues = error.issues.map(issue => \n ` - ${issue.path.join('.')}: ${issue.message}`\n ).join('\\n');\n \n throw new Error(\n `Configuration validation failed:\\n${issues}\\n\\n` +\n 'Please check your environment variables:\\n' +\n ' - MEMORYRELAY_API_KEY (required, starts with \"mem_\")\\n' +\n ' - MEMORYRELAY_API_URL (optional, default: https://api.memoryrelay.net)\\n' +\n ' - MEMORYRELAY_AGENT_ID (optional, auto-detected)\\n' +\n ' - MEMORYRELAY_TIMEOUT (optional, default: 30000)\\n' +\n ' - MEMORYRELAY_LOG_LEVEL (optional, default: info)'\n );\n }\n throw error;\n }\n}\n\n/**\n * Get or generate agent ID\n */\nexport function getAgentId(config: Config): string {\n if (config.agentId) {\n return config.agentId;\n }\n\n // Auto-generate from hostname\n const hostname = process.env.HOSTNAME || 'unknown';\n return `agent-${hostname.slice(0, 8)}`;\n}\n","/**\n * Security-hardened logger for MCP server\n * \n * - All output to stderr (stdout reserved for MCP protocol)\n * - Automatic masking of API keys (anything starting with \"mem_\")\n * - No internal paths in error messages\n */\n\ntype LogLevel = 'debug' | 'info' | 'warn' | 'error';\n\nconst LOG_LEVELS: Record<LogLevel, number> = {\n debug: 0,\n info: 1,\n warn: 2,\n error: 3,\n};\n\nexport class Logger {\n private minLevel: number;\n\n constructor(level: LogLevel = 'info') {\n this.minLevel = LOG_LEVELS[level];\n }\n\n /**\n * Mask sensitive data in log messages\n * - API keys starting with \"mem_\" are masked\n * - Internal paths are sanitized\n */\n private sanitize(message: string): string {\n let sanitized = message;\n\n // Mask API keys (mem_xxx -> mem_****)\n sanitized = sanitized.replace(/mem_[a-zA-Z0-9_-]+/g, 'mem_****');\n\n // Remove internal paths (anything that looks like a file path)\n sanitized = sanitized.replace(/\\/[a-zA-Z0-9_\\-./]+\\.(ts|js|json)/g, '<file>');\n sanitized = sanitized.replace(/at\\s+[^\\s]+\\s+\\([^)]+\\)/g, 'at <location>');\n\n return sanitized;\n }\n\n /**\n * Format log message with timestamp and level\n */\n private format(level: LogLevel, message: string, data?: unknown): string {\n const timestamp = new Date().toISOString();\n const sanitizedMessage = this.sanitize(message);\n \n let output = `[${timestamp}] [${level.toUpperCase()}] ${sanitizedMessage}`;\n \n if (data !== undefined) {\n const sanitizedData = this.sanitize(JSON.stringify(data, null, 2));\n output += `\\n${sanitizedData}`;\n }\n \n return output;\n }\n\n debug(message: string, data?: unknown): void {\n if (this.minLevel <= LOG_LEVELS.debug) {\n console.error(this.format('debug', message, data));\n }\n }\n\n info(message: string, data?: unknown): void {\n if (this.minLevel <= LOG_LEVELS.info) {\n console.error(this.format('info', message, data));\n }\n }\n\n warn(message: string, data?: unknown): void {\n if (this.minLevel <= LOG_LEVELS.warn) {\n console.error(this.format('warn', message, data));\n }\n }\n\n error(message: string, data?: unknown): void {\n if (this.minLevel <= LOG_LEVELS.error) {\n console.error(this.format('error', message, data));\n }\n }\n}\n\n// Export singleton instance\nlet logger: Logger;\n\nexport function initLogger(level: LogLevel = 'info'): Logger {\n logger = new Logger(level);\n return logger;\n}\n\nexport function getLogger(): Logger {\n if (!logger) {\n logger = new Logger();\n }\n return logger;\n}\n","/**\n * MCP Server implementation for MemoryRelay\n */\n\nimport { Server } from '@modelcontextprotocol/sdk/server/index.js';\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport {\n CallToolRequestSchema,\n ListToolsRequestSchema,\n} from '@modelcontextprotocol/sdk/types.js';\nimport { z } from 'zod';\nimport { MemoryRelayClient } from './client.js';\nimport { getLogger } from './logger.js';\nimport type { ClientConfig } from './types.js';\n\n/**\n * HTML-encode string to prevent XSS\n */\nfunction sanitizeHtml(str: string): string {\n return str\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n .replace(/'/g, '&#x27;')\n .replace(/\\//g, '&#x2F;');\n}\n\n/**\n * Validate UUID format\n */\nconst uuidSchema = z.string().uuid();\n\nfunction validateUuid(id: string, fieldName: string = 'id'): void {\n const result = uuidSchema.safeParse(id);\n if (!result.success) {\n throw new Error(`Invalid ${fieldName}: must be a valid UUID`);\n }\n}\n\nexport class MemoryRelayMCPServer {\n private server: Server;\n private client: MemoryRelayClient;\n private logger = getLogger();\n\n constructor(config: ClientConfig) {\n this.client = new MemoryRelayClient(config);\n \n this.server = new Server(\n {\n name: '@memoryrelay/mcp-server',\n version: '0.1.0',\n },\n {\n capabilities: {\n tools: {},\n },\n }\n );\n\n this.setupHandlers();\n this.logger.info('MCP server initialized');\n }\n\n /**\n * Setup MCP protocol handlers\n */\n private setupHandlers(): void {\n // List available tools\n this.server.setRequestHandler(ListToolsRequestSchema, async () => ({\n tools: [\n {\n name: 'memory_store',\n description: 'Store a new memory. Use this to save important information, facts, preferences, or context that should be remembered for future conversations.',\n inputSchema: {\n type: 'object',\n properties: {\n content: {\n type: 'string',\n description: 'The memory content to store. Be specific and include relevant context.',\n },\n metadata: {\n type: 'object',\n description: 'Optional key-value metadata to attach to the memory',\n additionalProperties: { type: 'string' },\n },\n },\n required: ['content'],\n },\n },\n {\n name: 'memory_search',\n description: 'Search memories using natural language. Returns the most relevant memories based on semantic similarity to the query.',\n inputSchema: {\n type: 'object',\n properties: {\n query: {\n type: 'string',\n description: 'Natural language search query',\n },\n limit: {\n type: 'number',\n description: 'Maximum number of results to return (1-50)',\n minimum: 1,\n maximum: 50,\n default: 10,\n },\n threshold: {\n type: 'number',\n description: 'Minimum similarity threshold (0-1)',\n minimum: 0,\n maximum: 1,\n default: 0.5,\n },\n },\n required: ['query'],\n },\n },\n {\n name: 'memory_list',\n description: 'List recent memories chronologically. Use to review what has been remembered.',\n inputSchema: {\n type: 'object',\n properties: {\n limit: {\n type: 'number',\n description: 'Number of memories to return (1-100)',\n minimum: 1,\n maximum: 100,\n default: 20,\n },\n offset: {\n type: 'number',\n description: 'Offset for pagination',\n minimum: 0,\n default: 0,\n },\n },\n },\n },\n {\n name: 'memory_get',\n description: 'Retrieve a specific memory by its ID.',\n inputSchema: {\n type: 'object',\n properties: {\n id: {\n type: 'string',\n description: 'The memory ID (UUID) to retrieve',\n },\n },\n required: ['id'],\n },\n },\n {\n name: 'memory_update',\n description: 'Update the content of an existing memory. Use to correct or expand stored information.',\n inputSchema: {\n type: 'object',\n properties: {\n id: {\n type: 'string',\n description: 'The memory ID (UUID) to update',\n },\n content: {\n type: 'string',\n description: 'The new content to replace the existing memory',\n },\n metadata: {\n type: 'object',\n description: 'Updated metadata (replaces existing)',\n additionalProperties: { type: 'string' },\n },\n },\n required: ['id', 'content'],\n },\n },\n {\n name: 'memory_delete',\n description: 'Permanently delete a memory. Use sparingly - memories are valuable context.',\n inputSchema: {\n type: 'object',\n properties: {\n id: {\n type: 'string',\n description: 'The memory ID (UUID) to delete',\n },\n },\n required: ['id'],\n },\n },\n {\n name: 'entity_create',\n description: 'Create a named entity (person, place, organization, project, concept) for the knowledge graph. Entities help organize and connect memories.',\n inputSchema: {\n type: 'object',\n properties: {\n name: {\n type: 'string',\n minLength: 1,\n maxLength: 200,\n description: 'Entity name (1-200 characters)',\n },\n type: {\n type: 'string',\n enum: ['person', 'place', 'organization', 'project', 'concept', 'other'],\n description: 'Entity type classification',\n },\n metadata: {\n type: 'object',\n description: 'Optional key-value metadata',\n additionalProperties: { type: 'string' },\n },\n },\n required: ['name', 'type'],\n },\n },\n {\n name: 'entity_link',\n description: 'Link an entity to a memory to establish relationships in the knowledge graph.',\n inputSchema: {\n type: 'object',\n properties: {\n entity_id: {\n type: 'string',\n description: 'Entity UUID',\n },\n memory_id: {\n type: 'string',\n description: 'Memory UUID',\n },\n relationship: {\n type: 'string',\n description: 'Relationship type (e.g., \"mentioned_in\", \"created_by\", \"relates_to\")',\n default: 'mentioned_in',\n },\n },\n required: ['entity_id', 'memory_id'],\n },\n },\n {\n name: 'memory_health',\n description: 'Check API connectivity and health status.',\n inputSchema: {\n type: 'object',\n properties: {},\n },\n },\n ],\n }));\n\n // Handle tool calls\n this.server.setRequestHandler(CallToolRequestSchema, async (request) => {\n const { name, arguments: args } = request.params;\n\n this.logger.debug(`Tool called: ${name}`, args);\n\n try {\n switch (name) {\n case 'memory_store': {\n const memory = await this.client.storeMemory(\n args.content as string,\n args.metadata as Record<string, string> | undefined\n );\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(memory, null, 2),\n },\n ],\n };\n }\n\n case 'memory_search': {\n const results = await this.client.searchMemories(\n args.query as string,\n args.limit as number | undefined,\n args.threshold as number | undefined\n );\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(\n { memories: results, total: results.length },\n null,\n 2\n ),\n },\n ],\n };\n }\n\n case 'memory_list': {\n const response = await this.client.listMemories(\n args.limit as number | undefined,\n args.offset as number | undefined\n );\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(response, null, 2),\n },\n ],\n };\n }\n\n case 'memory_get': {\n const id = args.id as string;\n validateUuid(id, 'memory_id');\n \n const memory = await this.client.getMemory(id);\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(memory, null, 2),\n },\n ],\n };\n }\n\n case 'memory_update': {\n const id = args.id as string;\n validateUuid(id, 'memory_id');\n \n const memory = await this.client.updateMemory(\n id,\n args.content as string,\n args.metadata as Record<string, string> | undefined\n );\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(memory, null, 2),\n },\n ],\n };\n }\n\n case 'memory_delete': {\n const id = args.id as string;\n validateUuid(id, 'memory_id');\n \n await this.client.deleteMemory(id);\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(\n { success: true, message: 'Memory deleted successfully' },\n null,\n 2\n ),\n },\n ],\n };\n }\n\n case 'entity_create': {\n // Validate input schema\n const entitySchema = z.object({\n name: z.string().min(1).max(200),\n type: z.enum(['person', 'place', 'organization', 'project', 'concept', 'other']),\n metadata: z.record(z.string()).optional(),\n });\n\n const validatedInput = entitySchema.parse(args);\n \n // Sanitize name to prevent XSS\n const sanitizedName = sanitizeHtml(validatedInput.name);\n \n const entity = await this.client.createEntity(\n sanitizedName,\n validatedInput.type,\n validatedInput.metadata\n );\n \n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(entity, null, 2),\n },\n ],\n };\n }\n\n case 'entity_link': {\n // Validate input schema\n const linkSchema = z.object({\n entity_id: z.string().uuid(),\n memory_id: z.string().uuid(),\n relationship: z.string().default('mentioned_in'),\n });\n\n const validatedInput = linkSchema.parse(args);\n \n await this.client.linkEntity(\n validatedInput.entity_id,\n validatedInput.memory_id,\n validatedInput.relationship\n );\n \n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(\n {\n success: true,\n message: 'Entity linked to memory successfully',\n entity_id: validatedInput.entity_id,\n memory_id: validatedInput.memory_id,\n relationship: validatedInput.relationship,\n },\n null,\n 2\n ),\n },\n ],\n };\n }\n\n case 'memory_health': {\n const health = await this.client.healthCheck();\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(health, null, 2),\n },\n ],\n };\n }\n\n default:\n throw new Error(`Unknown tool: ${name}`);\n }\n } catch (error) {\n let errorMessage = 'Unknown error';\n let errorDetails: unknown = undefined;\n\n if (error instanceof z.ZodError) {\n errorMessage = 'Validation error';\n errorDetails = error.errors;\n } else if (error instanceof Error) {\n errorMessage = error.message;\n }\n\n this.logger.error(`Tool execution failed: ${name}`, {\n error: errorMessage,\n details: errorDetails,\n });\n \n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(\n {\n error: 'Tool execution failed',\n message: errorMessage,\n details: errorDetails,\n },\n null,\n 2\n ),\n },\n ],\n isError: true,\n };\n }\n });\n }\n\n /**\n * Start the MCP server with STDIO transport\n */\n async start(): Promise<void> {\n const transport = new StdioServerTransport();\n await this.server.connect(transport);\n this.logger.info('MCP server started on STDIO');\n }\n}\n","/**\n * MemoryRelay API client with retry logic and error handling\n */\n\nimport type {\n Memory,\n Entity,\n SearchResult,\n ListResponse,\n ClientConfig,\n EntityType,\n} from './types.js';\nimport { getLogger } from './logger.js';\n\n// Retry configuration\nconst MAX_RETRIES = 3;\nconst INITIAL_DELAY_MS = 1000;\nconst MAX_CONTENT_SIZE = 50 * 1024; // 50KB\n\n/**\n * Exponential backoff retry wrapper\n */\nasync function withRetry<T>(\n fn: () => Promise<T>,\n retries: number = MAX_RETRIES\n): Promise<T> {\n let lastError: Error | undefined;\n \n for (let attempt = 0; attempt <= retries; attempt++) {\n try {\n return await fn();\n } catch (error) {\n lastError = error instanceof Error ? error : new Error(String(error));\n \n // Don't retry on certain errors\n if (\n lastError.message.includes('401') ||\n lastError.message.includes('403') ||\n lastError.message.includes('404') ||\n lastError.message.includes('400')\n ) {\n throw lastError;\n }\n \n // On last attempt, throw the error\n if (attempt === retries) {\n throw lastError;\n }\n \n // Exponential backoff with jitter\n const delay = INITIAL_DELAY_MS * Math.pow(2, attempt);\n const jitter = Math.random() * 0.3 * delay;\n await new Promise(resolve => setTimeout(resolve, delay + jitter));\n }\n }\n \n throw lastError || new Error('Retry failed');\n}\n\n/**\n * Mask API key in error messages for security\n */\nfunction maskApiKey(message: string, apiKey: string): string {\n if (!apiKey) return message;\n const maskedKey = apiKey.substring(0, 8) + '***';\n return message.replace(new RegExp(apiKey, 'g'), maskedKey);\n}\n\nexport class MemoryRelayClient {\n private config: ClientConfig;\n private logger = getLogger();\n\n constructor(config: ClientConfig) {\n this.config = config;\n this.logger.info('MemoryRelay client initialized', {\n apiUrl: config.apiUrl,\n agentId: config.agentId,\n });\n }\n\n /**\n * Make authenticated HTTP request to MemoryRelay API with retry logic\n */\n private async request<T>(\n method: string,\n path: string,\n body?: unknown\n ): Promise<T> {\n return withRetry(async () => {\n const url = `${this.config.apiUrl}${path}`;\n \n this.logger.debug(`API request: ${method} ${path}`);\n\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), this.config.timeout);\n\n try {\n const response = await fetch(url, {\n method,\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${this.config.apiKey}`,\n 'User-Agent': '@memoryrelay/mcp-server',\n },\n body: body ? JSON.stringify(body) : undefined,\n signal: controller.signal,\n });\n\n if (!response.ok) {\n // Handle rate limiting with retry\n if (response.status === 429) {\n const retryAfter = response.headers.get('Retry-After');\n const waitMs = retryAfter ? parseInt(retryAfter) * 1000 : 5000;\n this.logger.warn(`Rate limited, waiting ${waitMs}ms`);\n await new Promise(resolve => setTimeout(resolve, waitMs));\n throw new Error(`Rate limited: 429 - Retry after ${waitMs}ms`);\n }\n\n const errorData = await response.json().catch(() => ({}));\n const errorMsg = `API request failed: ${response.status} ${response.statusText}` +\n (errorData.message ? ` - ${errorData.message}` : '');\n \n // Mask API key in error message\n throw new Error(maskApiKey(errorMsg, this.config.apiKey));\n }\n\n const data = await response.json();\n this.logger.debug(`API response: ${method} ${path}`, { status: response.status });\n \n return data as T;\n } catch (error) {\n if (error instanceof Error) {\n if (error.name === 'AbortError') {\n throw new Error(`Request timeout after ${this.config.timeout}ms`);\n }\n // Mask API key in all error messages\n error.message = maskApiKey(error.message, this.config.apiKey);\n }\n throw error;\n } finally {\n clearTimeout(timeout);\n }\n });\n }\n\n /**\n * Validate content size\n */\n private validateContentSize(content: string): void {\n if (content.length > MAX_CONTENT_SIZE) {\n throw new Error(`Content exceeds maximum size of ${MAX_CONTENT_SIZE} bytes`);\n }\n }\n\n /**\n * Store a new memory\n */\n async storeMemory(content: string, metadata?: Record<string, string>): Promise<Memory> {\n this.validateContentSize(content);\n \n return this.request<Memory>('POST', '/v1/memories/memories', {\n content,\n metadata,\n agent_id: this.config.agentId,\n });\n }\n\n /**\n * Search memories using semantic search\n */\n async searchMemories(\n query: string,\n limit: number = 10,\n threshold: number = 0.5\n ): Promise<SearchResult[]> {\n this.validateContentSize(query);\n \n const response = await this.request<{ data: SearchResult[] }>(\n 'POST',\n '/v1/memories/memories/search',\n { query, limit, threshold, agent_id: this.config.agentId }\n );\n return response.data;\n }\n\n /**\n * List recent memories with pagination\n */\n async listMemories(limit: number = 20, offset: number = 0): Promise<ListResponse<Memory>> {\n return this.request<ListResponse<Memory>>(\n 'GET',\n `/v1/memories/memories?limit=${limit}&offset=${offset}`\n );\n }\n\n /**\n * Get a specific memory by ID\n */\n async getMemory(id: string): Promise<Memory> {\n return this.request<Memory>('GET', `/v1/memories/memories/${id}`);\n }\n\n /**\n * Update an existing memory\n */\n async updateMemory(\n id: string,\n content: string,\n metadata?: Record<string, string>\n ): Promise<Memory> {\n this.validateContentSize(content);\n \n return this.request<Memory>('PATCH', `/v1/memories/memories/${id}`, {\n content,\n metadata,\n });\n }\n\n /**\n * Delete a memory\n */\n async deleteMemory(id: string): Promise<void> {\n await this.request<void>('DELETE', `/v1/memories/memories/${id}`);\n }\n\n /**\n * Create a named entity\n */\n async createEntity(\n name: string,\n type: EntityType,\n metadata?: Record<string, string>\n ): Promise<Entity> {\n this.validateContentSize(name);\n \n return this.request<Entity>('POST', '/v1/entities', {\n name,\n type,\n metadata,\n });\n }\n\n /**\n * Link an entity to a memory\n */\n async linkEntity(\n entityId: string,\n memoryId: string,\n relationship: string = 'mentioned_in'\n ): Promise<void> {\n await this.request<void>('POST', '/v1/entities/links', {\n entity_id: entityId,\n memory_id: memoryId,\n relationship,\n });\n }\n\n /**\n * Get an entity by ID\n */\n async getEntity(id: string): Promise<Entity> {\n return this.request<Entity>('GET', `/v1/entities/${id}`);\n }\n\n /**\n * List entities with pagination\n */\n async listEntities(limit: number = 20, offset: number = 0): Promise<ListResponse<Entity>> {\n return this.request<ListResponse<Entity>>(\n 'GET',\n `/v1/entities?limit=${limit}&offset=${offset}`\n );\n }\n\n /**\n * Delete an entity\n */\n async deleteEntity(id: string): Promise<void> {\n await this.request<void>('DELETE', `/v1/entities/${id}`);\n }\n\n /**\n * Health check - verify API connectivity\n */\n async healthCheck(): Promise<{ status: string; message: string }> {\n try {\n // Simple GET request to check API is reachable\n await this.request<{ status: string }>('GET', '/v1/health');\n return {\n status: 'healthy',\n message: 'API connection successful',\n };\n } catch (error) {\n const errorMsg = error instanceof Error ? error.message : 'Unknown error';\n return {\n status: 'unhealthy',\n message: `API connection failed: ${errorMsg}`,\n };\n }\n }\n}\n","#!/usr/bin/env node\n/**\n * MemoryRelay MCP Server - Entry Point\n * \n * Provides persistent memory storage for AI agents via Model Context Protocol\n */\n\nimport { loadConfig, getAgentId } from './config.js';\nimport { initLogger, getLogger } from './logger.js';\nimport { MemoryRelayMCPServer } from './server.js';\n\nasync function main() {\n try {\n // Load and validate configuration\n const config = loadConfig();\n \n // Initialize logger with configured level\n initLogger(config.logLevel);\n const logger = getLogger();\n\n logger.info('Starting MemoryRelay MCP server');\n\n // Get or generate agent ID\n const agentId = getAgentId(config);\n\n // Create and start MCP server\n const server = new MemoryRelayMCPServer({\n apiKey: config.apiKey,\n apiUrl: config.apiUrl,\n agentId,\n timeout: config.timeout,\n });\n\n await server.start();\n\n // Keep process alive\n process.on('SIGINT', () => {\n logger.info('Received SIGINT, shutting down gracefully');\n process.exit(0);\n });\n\n process.on('SIGTERM', () => {\n logger.info('Received SIGTERM, shutting down gracefully');\n process.exit(0);\n });\n\n } catch (error) {\n const logger = getLogger();\n \n if (error instanceof Error) {\n logger.error('Fatal error:', { message: error.message });\n \n // Print user-friendly error to stderr\n console.error('\\nāŒ Failed to start MemoryRelay MCP server\\n');\n console.error(error.message);\n console.error('\\nFor help, see: https://github.com/Alteriom/ai-memory-service/tree/main/mcp\\n');\n } else {\n logger.error('Fatal error:', { error });\n console.error('\\nāŒ An unexpected error occurred\\n');\n }\n \n process.exit(1);\n }\n}\n\nmain();\n"],"mappings":"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","names":["z","z","logger"]}
@@ -0,0 +1,449 @@
1
+ # Security Guide
2
+
3
+ This document outlines the security measures implemented in the MemoryRelay MCP server and provides best practices for secure deployment.
4
+
5
+ ---
6
+
7
+ ## šŸ” Overview
8
+
9
+ The MemoryRelay MCP server is designed with security as a top priority:
10
+
11
+ - **No credential storage** - API keys never written to disk
12
+ - **Automatic key masking** - Sensitive data hidden in all logs
13
+ - **Input validation** - All inputs validated before processing
14
+ - **Error sanitization** - No internal paths or sensitive data leaked
15
+ - **STDIO isolation** - Logs strictly to stderr per MCP spec
16
+
17
+ ---
18
+
19
+ ## šŸ”‘ API Key Handling
20
+
21
+ ### Best Practices
22
+
23
+ #### āœ… DO
24
+
25
+ - Store API keys in environment variables only
26
+ - Use your MCP client's configuration file to set environment variables
27
+ - Rotate API keys regularly (recommended: every 90 days)
28
+ - Use different API keys for different agents/environments
29
+ - Revoke compromised keys immediately via the MemoryRelay dashboard
30
+
31
+ #### āŒ DON'T
32
+
33
+ - Never commit API keys to version control
34
+ - Never hardcode API keys in configuration files
35
+ - Never share API keys between production and development
36
+ - Never log API keys manually in your own code
37
+ - Never expose API keys in command-line arguments (use env vars)
38
+
39
+ ### How Keys Are Protected
40
+
41
+ The MCP server automatically masks any string starting with `mem_` in:
42
+
43
+ - Application logs (stderr)
44
+ - Error messages
45
+ - Debug output
46
+ - API request/response logging
47
+
48
+ **Example:**
49
+
50
+ ```typescript
51
+ // In logs, this:
52
+ MEMORYRELAY_API_KEY=mem_prod_abc123xyz789
53
+
54
+ // Becomes:
55
+ MEMORYRELAY_API_KEY=mem_prod_***
56
+ ```
57
+
58
+ ### Key Format
59
+
60
+ Valid API keys have the format:
61
+
62
+ ```
63
+ mem_{environment}_{random_string}
64
+ ```
65
+
66
+ Where `{environment}` is typically:
67
+ - `prod` - Production keys
68
+ - `dev` - Development keys
69
+ - `test` - Testing keys
70
+
71
+ ---
72
+
73
+ ## šŸŒ Environment Variables
74
+
75
+ ### Recommended Configuration
76
+
77
+ Always configure via your MCP client's environment block:
78
+
79
+ **OpenClaw** (`~/.openclaw/openclaw.json`):
80
+ ```json
81
+ {
82
+ "mcpServers": {
83
+ "memoryrelay": {
84
+ "command": "npx",
85
+ "args": ["-y", "@memoryrelay/mcp-server"],
86
+ "env": {
87
+ "MEMORYRELAY_API_KEY": "mem_prod_xxxxx",
88
+ "MEMORYRELAY_AGENT_ID": "iris",
89
+ "MEMORYRELAY_LOG_LEVEL": "info"
90
+ }
91
+ }
92
+ }
93
+ }
94
+ ```
95
+
96
+ **Claude Desktop**:
97
+ ```json
98
+ {
99
+ "mcpServers": {
100
+ "memoryrelay": {
101
+ "command": "npx",
102
+ "args": ["-y", "@memoryrelay/mcp-server"],
103
+ "env": {
104
+ "MEMORYRELAY_API_KEY": "mem_prod_xxxxx"
105
+ }
106
+ }
107
+ }
108
+ }
109
+ ```
110
+
111
+ ### File Permissions
112
+
113
+ Protect your configuration files:
114
+
115
+ ```bash
116
+ # macOS/Linux
117
+ chmod 600 ~/.openclaw/openclaw.json
118
+ chmod 600 ~/Library/Application\ Support/Claude/claude_desktop_config.json
119
+
120
+ # Verify permissions
121
+ ls -la ~/.openclaw/openclaw.json
122
+ # Should show: -rw------- (read/write for owner only)
123
+ ```
124
+
125
+ ### Environment Variable Precedence
126
+
127
+ The server reads configuration in this order (first found wins):
128
+
129
+ 1. `MEMORYRELAY_API_KEY` - Explicit API key
130
+ 2. `MEMORYRELAY_API_URL` - Custom API endpoint (defaults to production)
131
+ 3. `MEMORYRELAY_AGENT_ID` - Agent identifier
132
+ 4. `OPENCLAW_AGENT_NAME` - OpenClaw auto-detection fallback
133
+ 5. Hostname-based generation - Last resort for agent ID
134
+
135
+ ---
136
+
137
+ ## šŸ“Š Logging & Data Handling
138
+
139
+ ### What Gets Logged
140
+
141
+ The MCP server logs to **stderr only** (stdout is reserved for MCP protocol):
142
+
143
+ #### Always Logged (INFO level):
144
+ - Server startup/shutdown events
145
+ - API connectivity status
146
+ - Tool invocation names (but NOT parameters)
147
+
148
+ #### Debug Level Only:
149
+ - Tool invocation parameters (with sensitive data masked)
150
+ - API request/response metadata (not full bodies)
151
+ - Validation errors with sanitized details
152
+
153
+ #### NEVER Logged:
154
+ - Full API key values
155
+ - Memory content (your actual data)
156
+ - Full API request/response bodies in production
157
+ - Internal file paths or stack traces
158
+
159
+ ### Log Levels
160
+
161
+ Configure via `MEMORYRELAY_LOG_LEVEL`:
162
+
163
+ | Level | Purpose | Use Case |
164
+ |-------|---------|----------|
165
+ | `error` | Critical errors only | Production (minimal logging) |
166
+ | `info` | Standard operations | Production (recommended) |
167
+ | `debug` | Detailed diagnostics | Development/troubleshooting |
168
+
169
+ **Production Recommendation:** Use `info` level
170
+
171
+ **Development:** Use `debug` to see tool parameters and API details
172
+
173
+ ### Sensitive Data Masking
174
+
175
+ Automatic masking patterns:
176
+
177
+ - **API Keys**: `mem_*` → `mem_prod_***`
178
+ - **UUIDs**: Logged but not considered sensitive (they're already access-controlled)
179
+ - **Usernames/Emails**: Not currently logged
180
+
181
+ ### Example Log Output
182
+
183
+ ```
184
+ [2026-02-12T00:00:00.000Z] INFO: Starting MemoryRelay MCP server
185
+ [2026-02-12T00:00:00.100Z] INFO: MCP server initialized
186
+ [2026-02-12T00:00:00.200Z] INFO: MCP server started on STDIO
187
+ [2026-02-12T00:00:10.000Z] DEBUG: Tool called: memory_store {"content":"...","metadata":{...}}
188
+ [2026-02-12T00:00:10.100Z] DEBUG: API request: POST /memories (key: mem_prod_***)
189
+ ```
190
+
191
+ ---
192
+
193
+ ## āœ… Input Validation
194
+
195
+ ### Automatic Validation
196
+
197
+ All tool inputs are validated using Zod schemas:
198
+
199
+ #### Memory Content
200
+ - Type: String (required)
201
+ - No length limit (API enforces reasonable limits)
202
+ - HTML-encoded when used in entity names
203
+
204
+ #### Entity Names
205
+ - Type: String (required)
206
+ - Length: 1-200 characters
207
+ - Automatically sanitized to prevent XSS
208
+
209
+ #### UUIDs
210
+ - Format: Standard UUID v4
211
+ - Validated before API calls
212
+ - Invalid UUIDs rejected immediately
213
+
214
+ #### Metadata
215
+ - Type: Object with string values
216
+ - Keys and values are strings only
217
+ - No nested objects allowed
218
+
219
+ #### Numbers
220
+ - Limits and offsets: Non-negative integers
221
+ - Thresholds: Float between 0 and 1
222
+ - Timeouts: Positive integers
223
+
224
+ ### XSS Prevention
225
+
226
+ Entity names are HTML-encoded:
227
+
228
+ ```typescript
229
+ // Input:
230
+ name: "<script>alert('xss')</script>"
231
+
232
+ // Stored as:
233
+ name: "&lt;script&gt;alert(&#x27;xss&#x27;)&lt;/script&gt;"
234
+ ```
235
+
236
+ This prevents injection attacks if entity names are displayed in web interfaces.
237
+
238
+ ---
239
+
240
+ ## 🚫 Error Handling
241
+
242
+ ### Error Sanitization
243
+
244
+ Errors are sanitized before being returned to clients:
245
+
246
+ #### What's Included:
247
+ - User-friendly error message
248
+ - Error type (validation, network, API error)
249
+ - Field-level validation details (for Zod errors)
250
+
251
+ #### What's Excluded:
252
+ - Internal file paths
253
+ - Stack traces
254
+ - Environment variables
255
+ - API endpoint details
256
+ - Server configuration
257
+
258
+ ### Example Error Response
259
+
260
+ ```json
261
+ {
262
+ "error": "Tool execution failed",
263
+ "message": "Validation error",
264
+ "details": [
265
+ {
266
+ "code": "invalid_type",
267
+ "expected": "string",
268
+ "received": "number",
269
+ "path": ["content"],
270
+ "message": "Expected string, received number"
271
+ }
272
+ ]
273
+ }
274
+ ```
275
+
276
+ ---
277
+
278
+ ## šŸ”’ Rate Limiting
279
+
280
+ ### Client-Side Behavior
281
+
282
+ The MCP server respects API rate limits:
283
+
284
+ - **Timeout**: Default 30 seconds per request (configurable)
285
+ - **Retries**: No automatic retries (MCP clients should handle retries)
286
+ - **Backoff**: Not implemented (API returns 429 if rate limited)
287
+
288
+ ### API Rate Limits
289
+
290
+ The MemoryRelay API enforces these limits (as of 2026-02-12):
291
+
292
+ | Tier | Requests/min | Requests/day |
293
+ |------|--------------|--------------|
294
+ | Free | 20 | 1,000 |
295
+ | Pro | 100 | 10,000 |
296
+ | Enterprise | Custom | Custom |
297
+
298
+ **429 Responses**: When rate limited, the API returns:
299
+ ```json
300
+ {
301
+ "error": "Rate limit exceeded",
302
+ "retry_after": 60
303
+ }
304
+ ```
305
+
306
+ ### Handling Rate Limits
307
+
308
+ The MCP server will return rate limit errors to the client. Your MCP client (Claude Desktop, OpenClaw) should:
309
+
310
+ 1. Display the error to the user
311
+ 2. Retry after the `retry_after` period
312
+ 3. Consider caching frequently accessed memories
313
+
314
+ ---
315
+
316
+ ## šŸ›”ļø Security Checklist
317
+
318
+ Use this checklist when deploying the MCP server:
319
+
320
+ ### Configuration
321
+
322
+ - [ ] API key stored in environment variable (not hardcoded)
323
+ - [ ] Configuration file permissions set to 600 (owner read/write only)
324
+ - [ ] Different API keys for different environments (dev/prod)
325
+ - [ ] `MEMORYRELAY_LOG_LEVEL` set to `info` or `error` in production
326
+ - [ ] Custom `MEMORYRELAY_AGENT_ID` configured (optional but recommended)
327
+
328
+ ### Environment
329
+
330
+ - [ ] Node.js version 18+ (22+ recommended)
331
+ - [ ] MCP client is up to date (Claude Desktop, OpenClaw)
332
+ - [ ] Server runs with minimal privileges (not root/admin)
333
+ - [ ] Network connectivity to `api.memoryrelay.net` confirmed
334
+
335
+ ### Monitoring
336
+
337
+ - [ ] Server logs reviewed regularly for errors
338
+ - [ ] API key usage monitored via MemoryRelay dashboard
339
+ - [ ] Unusual activity alerts configured (if available)
340
+ - [ ] Regular API key rotation schedule established
341
+
342
+ ### Response Plan
343
+
344
+ - [ ] Procedure documented for API key compromise
345
+ - [ ] Backup MCP client configuration saved securely
346
+ - [ ] Contact information for MemoryRelay support saved
347
+ - [ ] Incident response plan includes MCP server logs
348
+
349
+ ---
350
+
351
+ ## 🚨 Security Issues
352
+
353
+ ### Reporting Vulnerabilities
354
+
355
+ If you discover a security vulnerability:
356
+
357
+ 1. **DO NOT** open a public GitHub issue
358
+ 2. Email security@memoryrelay.net with:
359
+ - Description of the vulnerability
360
+ - Steps to reproduce
361
+ - Potential impact
362
+ - Suggested fix (if any)
363
+
364
+ 3. Allow 90 days for response and patch before public disclosure
365
+
366
+ ### Security Updates
367
+
368
+ Monitor for security updates:
369
+
370
+ - **GitHub Releases**: https://github.com/memoryrelay/mcp-server/releases
371
+ - **npm Security Advisories**: `npm audit` in the project directory
372
+ - **Dependencies**: Regularly run `npm update` and `npm audit fix`
373
+
374
+ ### Known Limitations
375
+
376
+ Current known limitations:
377
+
378
+ 1. **No built-in encryption**: Memory content is encrypted at rest by the API, but not additionally encrypted by the MCP server
379
+ 2. **No client authentication**: MCP protocol doesn't provide client authentication (trust your MCP client)
380
+ 3. **No request signing**: API requests are authenticated via API key only
381
+ 4. **No rate limit caching**: Server doesn't cache rate limit state
382
+
383
+ These are either API-level concerns or MCP protocol limitations, not server bugs.
384
+
385
+ ---
386
+
387
+ ## šŸ”§ Advanced Security Configuration
388
+
389
+ ### Custom API Endpoint
390
+
391
+ For self-hosted MemoryRelay deployments:
392
+
393
+ ```json
394
+ {
395
+ "env": {
396
+ "MEMORYRELAY_API_URL": "https://memory.internal.company.com",
397
+ "MEMORYRELAY_API_KEY": "mem_prod_xxxxx"
398
+ }
399
+ }
400
+ ```
401
+
402
+ **Security Note:** Always use HTTPS for custom endpoints.
403
+
404
+ ### Network Isolation
405
+
406
+ For high-security environments:
407
+
408
+ 1. Use a firewall to restrict outbound connections to `api.memoryrelay.net` only
409
+ 2. Use a proxy server for MCP server traffic (set `HTTPS_PROXY` env var)
410
+ 3. Consider running MCP server in a sandboxed environment (Docker, VM)
411
+
412
+ ### Audit Logging
413
+
414
+ To enable comprehensive audit logging:
415
+
416
+ ```bash
417
+ # Run MCP server with debug logging redirected to a file
418
+ # (Your MCP client must support this - OpenClaw does)
419
+
420
+ # In openclaw.json:
421
+ {
422
+ "mcpServers": {
423
+ "memoryrelay": {
424
+ "command": "bash",
425
+ "args": ["-c", "npx -y @memoryrelay/mcp-server 2>> /var/log/memoryrelay-mcp.log"],
426
+ "env": {
427
+ "MEMORYRELAY_LOG_LEVEL": "debug",
428
+ "MEMORYRELAY_API_KEY": "mem_prod_xxxxx"
429
+ }
430
+ }
431
+ }
432
+ }
433
+ ```
434
+
435
+ **Warning:** Debug logs may contain sensitive information. Protect log files appropriately.
436
+
437
+ ---
438
+
439
+ ## šŸ“š Further Reading
440
+
441
+ - [MCP Security Best Practices](https://modelcontextprotocol.io/security)
442
+ - [MemoryRelay API Documentation](https://api.memoryrelay.net/docs)
443
+ - [OWASP Secure Coding Practices](https://owasp.org/www-project-secure-coding-practices-quick-reference-guide/)
444
+ - [Node.js Security Best Practices](https://nodejs.org/en/docs/guides/security/)
445
+
446
+ ---
447
+
448
+ **Last Updated:** 2026-02-12
449
+ **Version:** 0.1.0
package/package.json ADDED
@@ -0,0 +1,69 @@
1
+ {
2
+ "name": "@memoryrelay/mcp-server",
3
+ "version": "0.1.6",
4
+ "description": "MCP server for MemoryRelay - persistent memory for AI agents",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "type": "module",
8
+ "bin": {
9
+ "memoryrelay-mcp-server": "dist/index.js"
10
+ },
11
+ "files": [
12
+ "dist",
13
+ "README.md",
14
+ "docs"
15
+ ],
16
+ "scripts": {
17
+ "build": "tsup",
18
+ "dev": "tsup --watch",
19
+ "test": "vitest run",
20
+ "test:watch": "vitest",
21
+ "test:integration": "vitest run --config vitest.integration.config.ts tests/integration.test.ts",
22
+ "test:server": "vitest run tests/server.test.ts",
23
+ "test:security": "vitest run tests/security.test.ts",
24
+ "test:all": "npm test && npm run test:integration",
25
+ "test:coverage": "vitest run --coverage",
26
+ "type-check": "tsc --noEmit",
27
+ "lint": "echo 'Lint not configured yet'",
28
+ "prepublishOnly": "npm run build"
29
+ },
30
+ "keywords": [
31
+ "mcp",
32
+ "model-context-protocol",
33
+ "memory",
34
+ "ai",
35
+ "agent",
36
+ "openclaw",
37
+ "claude",
38
+ "persistent-memory",
39
+ "semantic-search",
40
+ "knowledge-graph"
41
+ ],
42
+ "author": "MemoryRelay Team",
43
+ "license": "MIT",
44
+ "repository": {
45
+ "type": "git",
46
+ "url": "https://github.com/memoryrelay/mcp-server.git"
47
+ },
48
+ "bugs": {
49
+ "url": "https://github.com/memoryrelay/mcp-server/issues"
50
+ },
51
+ "homepage": "https://github.com/memoryrelay/mcp-server#readme",
52
+ "publishConfig": {
53
+ "access": "public",
54
+ "registry": "https://registry.npmjs.org/"
55
+ },
56
+ "dependencies": {
57
+ "@modelcontextprotocol/sdk": "^1.26.0",
58
+ "zod": "^3.25.0"
59
+ },
60
+ "devDependencies": {
61
+ "@types/node": "^22.0.0",
62
+ "tsup": "^8.0.0",
63
+ "typescript": "^5.4.0",
64
+ "vitest": "^3.0.0"
65
+ },
66
+ "engines": {
67
+ "node": ">=18.0.0"
68
+ }
69
+ }