MemoryTypeOntology in MCP Memory Service: Complete Guide to 12 Base Types and 75 Sub-Types

The MemoryTypeOntology defines 12 base memory types and 75 specific sub-types that categorize why you store a memory (base) and what specific content it contains (sub-type), enabling precise semantic retrieval and project analytics.

The MemoryTypeOntology is the formal classification system at the heart of the doobidoo/mcp-memory-service repository, structuring how AI assistants categorize and retrieve contextual memories. Defined in src/mcp_memory_service/models/ontology.py, this taxonomy ensures every memory has a clear purpose and specific content category for optimal searchability and analytics.

The 12 Base Memory Types (The "Why")

The BaseMemoryType enum (lines 37‑64 of ontology.py) defines the root categories that describe the intent behind storing a memory. Select the base type that matches the fundamental purpose of the information.

observation

Use observation when capturing factual events, raw data, or actions that occurred. This is the default category for logging what happened during a session.

Common sub-types: code_edit, file_access, search, command, conversation, document, note, reference

decision

Use decision to record choices, recommendations, or configuration selections you made during development.

Common sub-types: architecture, tool_choice, approach, configuration

learning

Use learning for lessons derived from experience, including insights, best practices, and pitfalls to avoid.

Common sub-types: insight, best_practice, anti_pattern, gotcha

error

Use error to document problems, failures, exceptions, or timeouts that occurred or were discovered.

Common sub-types: bug, failure, exception, timeout

pattern

Use pattern for recurring constructs you want to reference later, such as code smells, design patterns, or workflow templates.

Common sub-types: recurring_issue, code_smell, design_pattern, workflow

planning

Use planning (Agile context) for sprint-related elements including goals, backlog items, estimates, and velocity metrics.

Common sub-types: sprint_goal, backlog_item, story_point_estimate, velocity, retrospective, standup_note, acceptance_criteria

ceremony

Use ceremony (Agile context) for structured recurring meetings such as reviews, planning sessions, and stand-ups.

Common sub-types: sprint_review, sprint_planning, daily_standup, retrospective_action, demo_feedback

milestone

Use milestone (Traditional PM) for high-level project checkpoints including deliverables, dependencies, risks, and deadlines.

Common sub-types: deliverable, dependency, risk, constraint, assumption, deadline

stakeholder

Use stakeholder (Traditional PM) for interactions with people or groups that affect the project.

Common sub-types: requirement, feedback, escalation, approval, change_request, status_update

meeting

Use meeting (Knowledge Work) for general meeting artifacts including agendas, minutes, and action items.

Common sub-types: action_item, attendee_note, agenda_item, follow_up, minutes

research

Use research (Knowledge Work) for structured investigation work including findings, comparisons, and hypotheses.

Common sub-types: finding, comparison, recommendation, source, hypothesis

communication

Use communication (Knowledge Work) for summaries of asynchronous communication such as emails, chats, and announcements.

Common sub-types: email_summary, chat_summary, announcement, request, response

The 75 Built-In Sub-Types (The "What")

Each base type contains a closed list of sub-types defined in the TAXONOMY mapping (lines 66‑161 of ontology.py). These provide granular classification for the specific content being stored.

Observation Sub-Types

  • code_edit – A code change (add/remove/modify)
  • file_access – Opening, reading, or writing a file
  • search – A query against code, docs, or logs
  • command – A CLI or tool command executed
  • conversation – A chat transcript or dialogue
  • document – A full-length document (e.g., design doc)
  • note – A short free-form note
  • reference – A link or citation to external knowledge

Decision Sub-Types

  • architecture – A high-level design choice
  • tool_choice – Selecting a library, framework, or service
  • approach – A methodological decision
  • configuration – A setting or parameter chosen

Learning Sub-Types

  • insight – A novel understanding
  • best_practice – A proven technique
  • anti_pattern – A known bad practice to avoid
  • gotcha – A surprising pitfall discovered

Error Sub-Types

  • bug – A defect in code
  • failure – A broader failure (e.g., build break)
  • exception – A raised exception trace
  • timeout – An operation that exceeded its deadline

Pattern Sub-Types

  • recurring_issue – A problem that shows up repeatedly
  • code_smell – A sign of deeper code quality issues
  • design_pattern – A reusable solution (e.g., Singleton)
  • workflow – A repeatable process template

Planning Sub-Types (Agile)

  • sprint_goal, backlog_item, story_point_estimate, velocity, retrospective, standup_note, acceptance_criteria

Ceremony Sub-Types (Agile)

  • sprint_review, sprint_planning, daily_standup, retrospective_action, demo_feedback

Milestone Sub-Types (Traditional)

  • deliverable, dependency, risk, constraint, assumption, deadline

Stakeholder Sub-Types (Traditional)

  • requirement, feedback, escalation, approval, change_request, status_update

Meeting Sub-Types (Knowledge Work)

  • action_item, attendee_note, agenda_item, follow_up, minutes

Research Sub-Types (Knowledge Work)

  • finding, comparison, recommendation, source, hypothesis

Communication Sub-Types (Knowledge Work)

  • email_summary, chat_summary, announcement, request, response

How to Programmatically Validate and Use Memory Types

The MemoryTypeOntology class provides static methods to validate types and retrieve hierarchy information (lines 22‑34 and 45‑61).

Validating a Memory Type

from mcp_memory_service.models.ontology import MemoryTypeOntology

# Check if a type is valid

is_valid = MemoryTypeOntology.validate_memory_type("bug")
print(is_valid)  # True

# Check invalid type

is_valid = MemoryTypeOntology.validate_memory_type("invalid_type")
print(is_valid)  # False

Retrieving Parent Base Types


# Get the parent base type for any sub-type

parent = MemoryTypeOntology.get_parent_type("code_edit")
print(parent)  # 'observation'

parent = MemoryTypeOntology.get_parent_type("architecture")
print(parent)  # 'decision'

Getting All Supported Types


# Retrieve all supported types including custom extensions

all_types = MemoryTypeOntology.get_all_types()
print(f"Total available types: {len(all_types)}")

Accessing the Full Taxonomy


# Get the merged taxonomy dictionary

tax = MemoryTypeOntology._get_merged_taxonomy()
print(tax["observation"])  # ['code_edit', 'file_access', ...]

Extending MemoryTypeOntology with Custom Types

The service supports runtime extension of the ontology via the MCP_CUSTOM_MEMORY_TYPES environment variable. The _load_custom_types_from_config() method (lines 96‑124) merges custom definitions with the built-in taxonomy.

Set the environment variable to a JSON object mapping base types to lists of new sub-types:

export MCP_CUSTOM_MEMORY_TYPES='{"planning": ["tech_spike", "ux_research"], "meeting": ["brainstorm"]}'

When loaded, these custom types are validated and merged into the taxonomy, making them available for validate_memory_type() and get_all_types() calls immediately.

Choosing the Right Memory Type: Decision Workflow

Follow this sequence when classifying a new memory:

  1. Identify the intent – Determine if you are recording something that happened (observation), a choice made (decision), a lesson learned (learning), a problem encountered (error), or a reusable construct (pattern)
  2. Select the base type – Match the intent to one of the 12 base types in BaseMemoryType
  3. Pinpoint the content – Choose the most specific sub-type from the 75 available options that captures the concrete content
  4. Validate – Use MemoryTypeOntology.validate_memory_type() to ensure the combination is supported

Example Classification Logic

def classify_memory(purpose: str, content: str) -> str:
    if purpose == "code_change":
        return "observation:code_edit"
    elif purpose == "design_decision":
        return "decision:architecture"
    elif purpose == "discovered_bug":
        return "error:bug"
    elif purpose == "lesson_learned":
        return "learning:insight"
    else:
        return "observation:note"

Summary

  • The MemoryTypeOntology in src/mcp_memory_service/models/ontology.py provides 12 base types (observation, decision, learning, error, pattern, planning, ceremony, milestone, stakeholder, meeting, research, communication) that define why you store a memory
  • 75 built-in sub-types define what specific content you are storing, organized under each base type in the TAXONOMY mapping (lines 66‑161)
  • Use validate_memory_type() to check type validity and get_parent_type() to navigate the hierarchy
  • Extend the ontology at runtime using the MCP_CUSTOM_MEMORY_TYPES environment variable and _load_custom_types_from_config()
  • Select base types based on intent and sub-types based on specific content for optimal retrieval and analytics

Frequently Asked Questions

How do I add a custom memory type not covered by the 75 built-in sub-types?

Set the MCP_CUSTOM_MEMORY_TYPES environment variable to a JSON object mapping existing base types to your new sub-types. The _load_custom_types_from_config() method merges these with the built-in TAXONOMY at runtime, making them available for validation and storage immediately.

What happens if I use an invalid memory type string?

The MemoryTypeOntology.validate_memory_type() method returns False for any type not present in the built-in taxonomy or custom extensions. The memory service typically rejects invalid types to maintain data quality and ensure analytics aggregation works correctly.

Can I retrieve all sub-types for a specific base type programmatically?

Yes. Use MemoryTypeOntology._get_merged_taxonomy() to access the full dictionary, then index into the base type name (e.g., taxonomy["observation"]) to get the list of valid sub-types. Alternatively, use get_parent_type() on any sub-type string to verify its base category.

When should I use "observation" versus "learning" for documenting code discoveries?

Use observation when neutrally logging what happened (e.g., "discovered deprecated function usage"). Use learning when capturing a derived insight or best practice (e.g., "always check for deprecation warnings before refactoring"). The distinction helps separate raw event logs from synthesized knowledge.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →