Module: ClaudeMemory::MCP::Handlers::QueryHandlers

Included in:
Tools
Defined in:
lib/claude_memory/mcp/handlers/query_handlers.rb

Overview

Query and recall tool handlers

Instance Method Summary collapse

Instance Method Details

#explain(args) ⇒ Object



47
48
49
50
51
52
53
# File 'lib/claude_memory/mcp/handlers/query_handlers.rb', line 47

def explain(args)
  scope = args["scope"] || "project"
  explanation = @recall.explain(args["fact_id"], scope: scope)
  return {error: "Fact not found in #{scope} database"} if explanation.is_a?(Core::NullExplanation)

  ResponseFormatter.format_explanation(explanation, scope)
end

#fact_graph(args) ⇒ Object



80
81
82
83
84
85
86
87
88
89
90
# File 'lib/claude_memory/mcp/handlers/query_handlers.rb', line 80

def fact_graph(args)
  fact_id = args["fact_id"]
  depth = args["depth"] || 2
  scope = args["scope"] || "project"

  graph = @recall.fact_graph(fact_id, depth: depth, scope: scope)

  return {error: "Fact #{fact_id} not found in #{scope} database"} if graph[:node_count] == 0

  graph
end

#recall(args) ⇒ Object



8
9
10
11
12
13
14
15
16
17
18
19
20
# File 'lib/claude_memory/mcp/handlers/query_handlers.rb', line 8

def recall(args)
  return database_not_found_error unless databases_exist?

  scope = extract_scope(args)
  limit = extract_limit(args)
  compact = args["compact"] == true
  query = args["query"]
  intent = extract_intent(args)
  results = @recall.query(query, limit: limit, scope: scope, include_raw_text: !compact, intent: intent)
  ResponseFormatter.format_recall_results(results, compact: compact, query: query)
rescue Sequel::DatabaseError, Sequel::DatabaseConnectionError, Errno::ENOENT => e
  classified_error(e, tool_name: "memory.recall")
end

#recall_details(args) ⇒ Object



30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/claude_memory/mcp/handlers/query_handlers.rb', line 30

def recall_details(args)
  fact_ids = args["fact_ids"]
  scope = args["scope"] || "project"

  explanations = fact_ids.map do |fact_id|
    explanation = @recall.explain(fact_id, scope: scope)
    next nil if explanation.is_a?(Core::NullExplanation)

    ResponseFormatter.format_detailed_explanation(explanation)
  end.compact

  {
    fact_count: explanations.size,
    facts: explanations
  }
end

#recall_index(args) ⇒ Object



22
23
24
25
26
27
28
# File 'lib/claude_memory/mcp/handlers/query_handlers.rb', line 22

def recall_index(args)
  scope = extract_scope(args)
  limit = extract_limit(args, default: 20)
  intent = extract_intent(args)
  results = @recall.query_index(args["query"], limit: limit, scope: scope, intent: intent)
  ResponseFormatter.format_index_results(args["query"], scope, results)
end

#recall_semantic(args) ⇒ Object



55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/claude_memory/mcp/handlers/query_handlers.rb', line 55

def recall_semantic(args)
  query = args["query"]
  mode = (args["mode"] || "both").to_sym
  scope = extract_scope(args)
  limit = extract_limit(args)
  compact = args["compact"] == true
  explain = args["explain"] == true
  intent = extract_intent(args)

  results = @recall.query_semantic(query, limit: limit, scope: scope, mode: mode, explain: explain, intent: intent)
  ResponseFormatter.format_semantic_results(query, mode.to_s, scope, results, compact: compact)
end

#search_concepts(args) ⇒ Object



68
69
70
71
72
73
74
75
76
77
78
# File 'lib/claude_memory/mcp/handlers/query_handlers.rb', line 68

def search_concepts(args)
  concepts = args["concepts"]
  scope = extract_scope(args)
  limit = extract_limit(args)
  compact = args["compact"] == true

  return {error: "Must provide 2-5 concepts"} unless (2..5).cover?(concepts.size)

  results = @recall.query_concepts(concepts, limit: limit, scope: scope)
  ResponseFormatter.format_concept_results(concepts, scope, results, compact: compact)
end

#undistilled(args) ⇒ Object



92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/claude_memory/mcp/handlers/query_handlers.rb', line 92

def undistilled(args)
  limit = args["limit"] || 3
  min_length = args["min_length"] || 200
  max_text = 2000

  items = collect_undistilled_items(limit: limit, min_length: min_length)

  {
    count: items.size,
    items: items.map { |item|
      {
        content_item_id: item[:id],
        occurred_at: item[:occurred_at],
        occurred_ago: Core::RelativeTime.format(item[:occurred_at]),
        project_path: item[:project_path],
        raw_text: Core::TextBuilder.truncate(item[:raw_text], max_text)
      }
    }
  }
end