memory

package
v0.16.8 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 14, 2025 License: Apache-2.0 Imports: 16 Imported by: 0

README

Memory Tool

The Memory Tool provides persistent knowledge graph storage capabilities for AI coding agents, allowing them to store, search, and retrieve memories across sessions using a structured entity-relation model.

Overview

The memory tool implements a knowledge graph system that stores:

  • Entities: Named nodes with types and observations (facts)
  • Relations: Directed connections between entities
  • Observations: Discrete facts attached to entities

Data is stored in JSONL (JSON Lines) format for efficient operations and concurrent access safety.

Features

Core Operations
  • create_entities: Create new entities with observations
  • create_relations: Create directed relationships between entities
  • add_observations: Add new facts to existing entities
  • delete_entities: Remove entities (cascades to relations)
  • delete_observations: Remove specific observations from entities
  • delete_relations: Remove specific relationships
  • read_graph: Retrieve the complete knowledge graph
  • search_nodes: Search entities using text queries with fuzzy matching
  • open_nodes: Retrieve specific entities by name
Advanced Features
  • Namespaces: Separate memory spaces for different projects/contexts
  • Fuzzy Search: Enhanced search using the sahilm/fuzzy library
  • Concurrent Access: File locking prevents data corruption
  • Atomic Operations: Temporary files ensure data consistency
  • Configurable Storage: Environment variable configuration

Configuration

Environment Variables
Variable Description Default
MEMORY_FILE_PATH Base directory or file path for memory storage ~/.mcp-devtools/
MEMORY_ENABLE_FUZZY_SEARCH Enable fuzzy search capabilities true
Storage Structure
~/.mcp-devtools/
├── default/
│   ├── memory.json      # Default namespace
│   └── memory.json.lock # Lock file
├── project_name/
│   ├── memory.json      # Project-specific namespace
│   └── memory.json.lock # Lock file
└── another_project/
    ├── memory.json
    └── memory.json.lock

Usage Examples

Creating Entities
{
  "operation": "create_entities",
  "namespace": "my_project",
  "data": {
    "entities": [
      {
        "name": "John_Doe",
        "entityType": "person",
        "observations": [
          "Software engineer at TechCorp",
          "Specialises in Go and Python",
          "Lives in San Francisco"
        ]
      },
      {
        "name": "TechCorp",
        "entityType": "company",
        "observations": [
          "Technology company",
          "Founded in 2010",
          "Headquarters in Silicon Valley"
        ]
      }
    ]
  }
}
Creating Relations
{
  "operation": "create_relations",
  "namespace": "my_project",
  "data": {
    "relations": [
      {
        "from": "John_Doe",
        "to": "TechCorp",
        "relationType": "works_at"
      }
    ]
  }
}
Searching Nodes
{
  "operation": "search_nodes",
  "namespace": "my_project",
  "data": {
    "query": "engineer"
  }
}
Adding Observations
{
  "operation": "add_observations",
  "namespace": "my_project",
  "data": {
    "observations": [
      {
        "entityName": "John_Doe",
        "contents": [
          "Recently promoted to senior engineer",
          "Working on microservices architecture"
        ]
      }
    ]
  }
}

Data Model

Entity Structure
type Entity struct {
    Name         string   `json:"name"`         // Unique identifier
    EntityType   string   `json:"entityType"`   // Category (person, company, etc.)
    Observations []string `json:"observations"` // List of facts
}
Relation Structure
type Relation struct {
    From         string `json:"from"`         // Source entity name
    To           string `json:"to"`           // Target entity name
    RelationType string `json:"relationType"` // Relationship type
}
Knowledge Graph Structure
type KnowledgeGraph struct {
    Entities  []Entity  `json:"entities"`
    Relations []Relation `json:"relations"`
}

Best Practices

Entity Naming
  • Use unique, descriptive names without spaces
  • Use underscores for multi-word names: John_Doe, TechCorp_Inc
  • Avoid special characters that might cause parsing issues
  • Keep names consistent across operations
Observations
  • Keep observations atomic (one fact per observation)
  • Use clear, descriptive language
  • Avoid redundant information
  • Update rather than duplicate similar facts
Relations
  • Use active voice for relation types: works_at, manages, created_by
  • Ensure both entities exist before creating relations
  • Use consistent relation type naming across your domain
Namespaces
  • Use descriptive namespace names for different projects/contexts
  • Default namespace is suitable for general-purpose storage
  • Consider data isolation needs when choosing namespaces

Error Handling

The memory tool provides comprehensive error handling:

  • Validation Errors: Invalid entity names, missing required fields
  • Relationship Errors: Relations referencing non-existent entities
  • File System Errors: Permission issues, disk space, corruption
  • Concurrency Errors: Lock acquisition failures, concurrent access

Performance Considerations

Search Performance
  • Fuzzy search is enabled by default but can be disabled for performance
  • Large knowledge graphs may experience slower search times
  • Consider splitting large datasets across multiple namespaces
Storage Performance
  • JSONL format provides efficient append operations
  • File locking ensures consistency but may impact concurrent performance
  • Regular backups recommended for important data
Memory Usage
  • Entire knowledge graph is loaded into memory for operations
  • Large graphs may require significant RAM
  • Consider splitting large datasets across namespaces

Concurrency and Safety

File Locking
  • Advisory file locking prevents corruption between processes
  • Read locks allow concurrent reads
  • Write locks ensure exclusive access during modifications
Atomic Operations
  • All write operations use temporary files with atomic rename
  • Ensures data consistency even if process is interrupted
  • Lock files prevent concurrent access during operations

Troubleshooting

Common Issues

Permission Denied

  • Ensure write permissions to the memory directory
  • Check if another process has exclusive locks

Entity Not Found

  • Verify entity names match exactly (case-sensitive)
  • Check if you're using the correct namespace

Lock Acquisition Failed

  • Another process may be accessing the same memory file
  • Wait and retry, or check for stuck processes

Corrupted Data

  • Check file permissions and disk space
  • Restore from backup if available
  • Validate JSON format manually
Debugging

Enable debug logging by setting the debug flag when running mcp-devtools:

./bin/mcp-devtools --debug stdio

Check memory file contents directly:

cat ~/.mcp-devtools/default/memory.json

Integration with AI Agents

The memory tool is designed specifically for AI coding agents:

Tool Descriptions
  • Comprehensive parameter descriptions help agents make informed decisions
  • Clear operation documentation prevents misuse
  • Warning annotations highlight destructive operations
Batch Operations
  • Most operations support batch processing for efficiency
  • Prefer batch operations over individual calls when possible
  • Reduces file I/O and improves performance
Search Capabilities
  • Fuzzy search helps agents find relevant information with partial queries
  • Multiple match types (exact, partial, fuzzy) provide flexibility
  • Search results include relevance scores for ranking

Architecture

Package Structure
internal/tools/memory/
├── memory.go     # MCP tool implementation
├── graph.go      # Knowledge graph operations
├── storage.go    # File I/O and persistence
├── types.go      # Data structures and types
└── README.md     # This documentation
Dependencies
  • github.com/sahilm/fuzzy - Fuzzy string matching
  • github.com/gofrs/flock - Cross-platform file locking
  • github.com/sirupsen/logrus - Structured logging
  • github.com/mark3labs/mcp-go/mcp - MCP framework
Design Principles
  • Simplicity: Clean, straightforward implementation
  • Reliability: Robust error handling and data consistency
  • Performance: Efficient operations for typical usage patterns
  • Extensibility: Modular design allows for future enhancements

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type AddObservationsRequest

type AddObservationsRequest struct {
	Observations []ObservationInput `json:"observations"`
}

AddObservationsRequest represents the input for adding observations

type AddObservationsResponse

type AddObservationsResponse struct {
	Results   []ObservationResult `json:"results"`
	Timestamp time.Time           `json:"timestamp"`
}

AddObservationsResponse represents the output of adding observations

type CreateEntitiesRequest

type CreateEntitiesRequest struct {
	Entities []Entity `json:"entities"`
}

CreateEntitiesRequest represents the input for creating entities

type CreateEntitiesResponse

type CreateEntitiesResponse struct {
	CreatedEntities []Entity  `json:"createdEntities"`
	Timestamp       time.Time `json:"timestamp"`
}

CreateEntitiesResponse represents the output of creating entities

type CreateRelationsRequest

type CreateRelationsRequest struct {
	Relations []Relation `json:"relations"`
}

CreateRelationsRequest represents the input for creating relations

type CreateRelationsResponse

type CreateRelationsResponse struct {
	CreatedRelations []Relation `json:"createdRelations"`
	Timestamp        time.Time  `json:"timestamp"`
}

CreateRelationsResponse represents the output of creating relations

type DeleteEntitiesRequest

type DeleteEntitiesRequest struct {
	EntityNames []string `json:"entityNames"`
}

DeleteEntitiesRequest represents the input for deleting entities

type DeleteObservationsRequest

type DeleteObservationsRequest struct {
	Deletions []ObservationDeletion `json:"deletions"`
}

DeleteObservationsRequest represents the input for deleting observations

type DeleteRelationsRequest

type DeleteRelationsRequest struct {
	Relations []Relation `json:"relations"`
}

DeleteRelationsRequest represents the input for deleting relations

type Entity

type Entity struct {
	Name         string   `json:"name"`
	EntityType   string   `json:"entityType"`
	Observations []string `json:"observations"`
}

Entity represents a node in the knowledge graph with a name, type, and observations

type GraphManager

type GraphManager struct {
	// contains filtered or unexported fields
}

GraphManager handles knowledge graph operations

func NewGraphManager

func NewGraphManager(logger *logrus.Logger) (*GraphManager, error)

NewGraphManager creates a new graph manager instance with default namespace

func NewGraphManagerWithNamespace

func NewGraphManagerWithNamespace(logger *logrus.Logger, namespace string) (*GraphManager, error)

NewGraphManagerWithNamespace creates a new graph manager instance with specified namespace

func (*GraphManager) AddObservations

func (gm *GraphManager) AddObservations(observations []ObservationInput) ([]ObservationResult, error)

AddObservations adds new observations to existing entities

func (*GraphManager) CreateEntities

func (gm *GraphManager) CreateEntities(entities []Entity) ([]Entity, error)

CreateEntities creates new entities, ignoring duplicates

func (*GraphManager) CreateRelations

func (gm *GraphManager) CreateRelations(relations []Relation) ([]Relation, error)

CreateRelations creates new relations, skipping duplicates

func (*GraphManager) DeleteEntities

func (gm *GraphManager) DeleteEntities(entityNames []string) error

DeleteEntities deletes entities and cascades to remove related relations

func (*GraphManager) DeleteObservations

func (gm *GraphManager) DeleteObservations(deletions []ObservationDeletion) error

DeleteObservations deletes specific observations from entities

func (*GraphManager) DeleteRelations

func (gm *GraphManager) DeleteRelations(relations []Relation) error

DeleteRelations deletes specific relations

func (*GraphManager) GetStorageInfo

func (gm *GraphManager) GetStorageInfo() (string, bool, error)

GetStorageInfo returns information about the storage

func (*GraphManager) OpenNodes

func (gm *GraphManager) OpenNodes(names []string) (*KnowledgeGraph, error)

OpenNodes retrieves specific entities by name

func (*GraphManager) ReadGraph

func (gm *GraphManager) ReadGraph() (*KnowledgeGraph, error)

ReadGraph returns the complete knowledge graph

func (*GraphManager) SearchNodes

func (gm *GraphManager) SearchNodes(query string) (*KnowledgeGraph, []SearchResult, error)

SearchNodes searches for nodes based on a query string

func (*GraphManager) SetNamespace

func (gm *GraphManager) SetNamespace(namespace string) error

SetNamespace changes the namespace for this graph manager

type KnowledgeGraph

type KnowledgeGraph struct {
	Entities  []Entity   `json:"entities"`
	Relations []Relation `json:"relations"`
}

KnowledgeGraph represents the complete graph structure

type MemoryOperationResponse

type MemoryOperationResponse struct {
	Message   string    `json:"message"`
	Timestamp time.Time `json:"timestamp"`
}

MemoryOperationResponse represents a generic response for operations that don't return specific data

type MemoryTool

type MemoryTool struct {
	// contains filtered or unexported fields
}

MemoryTool implements the MCP memory tool for knowledge graph operations

func (*MemoryTool) Definition

func (m *MemoryTool) Definition() mcp.Tool

Definition returns the tool's definition for MCP registration

func (*MemoryTool) Execute

func (m *MemoryTool) Execute(ctx context.Context, logger *logrus.Logger, cache *sync.Map, args map[string]interface{}) (*mcp.CallToolResult, error)

Execute executes the memory tool operations

type ObservationDeletion

type ObservationDeletion struct {
	EntityName   string   `json:"entityName"`
	Observations []string `json:"observations"`
}

ObservationDeletion represents observations to delete from a specific entity

type ObservationInput

type ObservationInput struct {
	EntityName string   `json:"entityName"`
	Contents   []string `json:"contents"`
}

ObservationInput represents observations to add to a specific entity

type ObservationResult

type ObservationResult struct {
	EntityName        string   `json:"entityName"`
	AddedObservations []string `json:"addedObservations"`
}

ObservationResult represents the result of adding observations to an entity

type OpenNodesRequest

type OpenNodesRequest struct {
	Names []string `json:"names"`
}

OpenNodesRequest represents the input for opening specific nodes

type Relation

type Relation struct {
	From         string `json:"from"`
	To           string `json:"to"`
	RelationType string `json:"relationType"`
}

Relation represents a directed connection between two entities

type SearchNodesRequest

type SearchNodesRequest struct {
	Query string `json:"query"`
}

SearchNodesRequest represents the input for searching nodes

type SearchNodesResponse

type SearchNodesResponse struct {
	Graph     KnowledgeGraph `json:"graph"`
	Results   []SearchResult `json:"results,omitempty"`
	Query     string         `json:"query"`
	Timestamp time.Time      `json:"timestamp"`
}

SearchNodesResponse represents the output of searching nodes

type SearchResult

type SearchResult struct {
	Entity    Entity  `json:"entity"`
	Score     float64 `json:"score,omitempty"`
	MatchType string  `json:"matchType,omitempty"` // "exact", "fuzzy", "partial"
}

SearchResult represents search results with relevance scoring

type Storage

type Storage struct {
	// contains filtered or unexported fields
}

Storage handles file I/O operations for the knowledge graph

func NewStorage

func NewStorage(logger *logrus.Logger) (*Storage, error)

NewStorage creates a new storage instance with the configured file path and default namespace

func NewStorageWithNamespace

func NewStorageWithNamespace(logger *logrus.Logger, namespace string) (*Storage, error)

NewStorageWithNamespace creates a new storage instance with the specified namespace

func (*Storage) BackupFile

func (s *Storage) BackupFile() error

BackupFile creates a backup of the current memory file

func (*Storage) FileExists

func (s *Storage) FileExists() bool

FileExists checks if the memory file exists

func (*Storage) GetFileInfo

func (s *Storage) GetFileInfo() (os.FileInfo, error)

GetFileInfo returns information about the memory file

func (*Storage) GetFilePath

func (s *Storage) GetFilePath() string

GetFilePath returns the configured file path

func (*Storage) LoadGraph

func (s *Storage) LoadGraph() (*KnowledgeGraph, error)

LoadGraph loads the complete knowledge graph from storage

func (*Storage) SaveGraph

func (s *Storage) SaveGraph(graph *KnowledgeGraph) error

SaveGraph saves the complete knowledge graph to storage using atomic operations

func (*Storage) SetNamespace

func (s *Storage) SetNamespace(namespace string) error

SetNamespace changes the namespace for this storage instance

type StoredEntity

type StoredEntity struct {
	Type         string   `json:"type"`
	Name         string   `json:"name"`
	EntityType   string   `json:"entityType"`
	Observations []string `json:"observations"`
}

StoredEntity represents an entity as stored in JSONL format

type StoredRelation

type StoredRelation struct {
	Type         string `json:"type"`
	From         string `json:"from"`
	To           string `json:"to"`
	RelationType string `json:"relationType"`
}

StoredRelation represents a relation as stored in JSONL format

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL