htm 0.0.15 → 0.0.17
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.
- checksums.yaml +4 -4
- data/.envrc +1 -0
- data/CHANGELOG.md +67 -0
- data/README.md +97 -1592
- data/bin/htm_mcp +31 -0
- data/config/database.yml +7 -4
- data/docs/getting-started/installation.md +31 -11
- data/docs/guides/mcp-server.md +456 -21
- data/docs/multi_framework_support.md +2 -2
- data/examples/mcp_client.rb +2 -2
- data/examples/rails_app/.gitignore +2 -0
- data/examples/rails_app/Gemfile +22 -0
- data/examples/rails_app/Gemfile.lock +438 -0
- data/examples/rails_app/Procfile.dev +1 -0
- data/examples/rails_app/README.md +98 -0
- data/examples/rails_app/Rakefile +5 -0
- data/examples/rails_app/app/assets/stylesheets/application.css +83 -0
- data/examples/rails_app/app/assets/stylesheets/inter-font.css +6 -0
- data/examples/rails_app/app/controllers/application_controller.rb +19 -0
- data/examples/rails_app/app/controllers/dashboard_controller.rb +27 -0
- data/examples/rails_app/app/controllers/files_controller.rb +205 -0
- data/examples/rails_app/app/controllers/memories_controller.rb +102 -0
- data/examples/rails_app/app/controllers/robots_controller.rb +44 -0
- data/examples/rails_app/app/controllers/search_controller.rb +46 -0
- data/examples/rails_app/app/controllers/tags_controller.rb +30 -0
- data/examples/rails_app/app/javascript/application.js +4 -0
- data/examples/rails_app/app/javascript/controllers/application.js +9 -0
- data/examples/rails_app/app/javascript/controllers/index.js +6 -0
- data/examples/rails_app/app/views/dashboard/index.html.erb +123 -0
- data/examples/rails_app/app/views/files/index.html.erb +108 -0
- data/examples/rails_app/app/views/files/new.html.erb +321 -0
- data/examples/rails_app/app/views/files/show.html.erb +130 -0
- data/examples/rails_app/app/views/layouts/application.html.erb +124 -0
- data/examples/rails_app/app/views/memories/_memory_card.html.erb +51 -0
- data/examples/rails_app/app/views/memories/deleted.html.erb +62 -0
- data/examples/rails_app/app/views/memories/edit.html.erb +35 -0
- data/examples/rails_app/app/views/memories/index.html.erb +81 -0
- data/examples/rails_app/app/views/memories/new.html.erb +71 -0
- data/examples/rails_app/app/views/memories/show.html.erb +126 -0
- data/examples/rails_app/app/views/robots/index.html.erb +106 -0
- data/examples/rails_app/app/views/robots/new.html.erb +36 -0
- data/examples/rails_app/app/views/robots/show.html.erb +79 -0
- data/examples/rails_app/app/views/search/index.html.erb +184 -0
- data/examples/rails_app/app/views/shared/_navbar.html.erb +52 -0
- data/examples/rails_app/app/views/shared/_stat_card.html.erb +52 -0
- data/examples/rails_app/app/views/tags/index.html.erb +131 -0
- data/examples/rails_app/app/views/tags/show.html.erb +67 -0
- data/examples/rails_app/bin/dev +8 -0
- data/examples/rails_app/bin/rails +4 -0
- data/examples/rails_app/bin/rake +4 -0
- data/examples/rails_app/config/application.rb +33 -0
- data/examples/rails_app/config/boot.rb +5 -0
- data/examples/rails_app/config/database.yml +15 -0
- data/examples/rails_app/config/environment.rb +5 -0
- data/examples/rails_app/config/importmap.rb +7 -0
- data/examples/rails_app/config/routes.rb +38 -0
- data/examples/rails_app/config/tailwind.config.js +35 -0
- data/examples/rails_app/config.ru +5 -0
- data/examples/rails_app/log/.keep +0 -0
- data/examples/rails_app/tmp/local_secret.txt +1 -0
- data/lib/htm/active_record_config.rb +2 -5
- data/lib/htm/configuration.rb +35 -2
- data/lib/htm/database.rb +3 -6
- data/lib/htm/mcp/cli.rb +333 -0
- data/lib/htm/mcp/group_tools.rb +476 -0
- data/lib/htm/mcp/resources.rb +89 -0
- data/lib/htm/mcp/server.rb +98 -0
- data/lib/htm/mcp/tools.rb +488 -0
- data/lib/htm/models/file_source.rb +5 -3
- data/lib/htm/railtie.rb +0 -4
- data/lib/htm/tasks.rb +7 -4
- data/lib/htm/version.rb +1 -1
- data/lib/tasks/htm.rake +6 -9
- metadata +59 -4
- data/bin/htm_mcp.rb +0 -621
data/lib/htm/mcp/cli.rb
ADDED
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class HTM
|
|
4
|
+
module MCP
|
|
5
|
+
# CLI commands for htm_mcp executable
|
|
6
|
+
module CLI
|
|
7
|
+
module_function
|
|
8
|
+
|
|
9
|
+
def print_help
|
|
10
|
+
puts <<~HELP
|
|
11
|
+
HTM MCP Server - Memory management for AI assistants
|
|
12
|
+
|
|
13
|
+
USAGE:
|
|
14
|
+
htm_mcp [COMMAND]
|
|
15
|
+
|
|
16
|
+
COMMANDS:
|
|
17
|
+
server Start the MCP server (default if no command given)
|
|
18
|
+
stdio Alias for server (for MCP client compatibility)
|
|
19
|
+
setup Initialize the database schema
|
|
20
|
+
init Alias for setup
|
|
21
|
+
verify Verify database connection and extensions
|
|
22
|
+
stats Show memory statistics
|
|
23
|
+
version Show HTM version
|
|
24
|
+
help Show this help message
|
|
25
|
+
|
|
26
|
+
ENVIRONMENT VARIABLES:
|
|
27
|
+
|
|
28
|
+
Environment:
|
|
29
|
+
HTM_ENV Environment name: development, test, production
|
|
30
|
+
(priority: HTM_ENV > RAILS_ENV > RACK_ENV > 'development')
|
|
31
|
+
|
|
32
|
+
Database (required):
|
|
33
|
+
HTM_DBURL PostgreSQL connection URL
|
|
34
|
+
Example: postgresql://user:pass@localhost:5432/htm_development
|
|
35
|
+
|
|
36
|
+
Database (alternative to HTM_DBURL):
|
|
37
|
+
HTM_DBNAME Database name
|
|
38
|
+
HTM_DBHOST Database host (default: localhost)
|
|
39
|
+
HTM_DBPORT Database port (default: 5432)
|
|
40
|
+
HTM_DBUSER Database username
|
|
41
|
+
HTM_DBPASS Database password
|
|
42
|
+
HTM_DBSSLMODE SSL mode (default: prefer)
|
|
43
|
+
|
|
44
|
+
LLM Providers:
|
|
45
|
+
HTM_EMBEDDING_PROVIDER Embedding provider (default: ollama)
|
|
46
|
+
HTM_EMBEDDING_MODEL Embedding model (default: nomic-embed-text:latest)
|
|
47
|
+
HTM_EMBEDDING_DIMENSIONS Embedding dimensions (default: 768)
|
|
48
|
+
HTM_TAG_PROVIDER Tag extraction provider (default: ollama)
|
|
49
|
+
HTM_TAG_MODEL Tag model (default: gemma3:latest)
|
|
50
|
+
HTM_PROPOSITION_PROVIDER Proposition provider (default: ollama)
|
|
51
|
+
HTM_PROPOSITION_MODEL Proposition model (default: gemma3:latest)
|
|
52
|
+
HTM_EXTRACT_PROPOSITIONS Enable propositions (default: false)
|
|
53
|
+
|
|
54
|
+
Ollama (default provider):
|
|
55
|
+
HTM_OLLAMA_URL Ollama server URL (default: http://localhost:11434)
|
|
56
|
+
|
|
57
|
+
Other Providers (set API keys as needed):
|
|
58
|
+
HTM_OPENAI_API_KEY OpenAI API key
|
|
59
|
+
HTM_ANTHROPIC_API_KEY Anthropic API key
|
|
60
|
+
HTM_GEMINI_API_KEY Google Gemini API key
|
|
61
|
+
HTM_AZURE_API_KEY Azure OpenAI API key
|
|
62
|
+
HTM_AZURE_ENDPOINT Azure OpenAI endpoint
|
|
63
|
+
|
|
64
|
+
Timeouts:
|
|
65
|
+
HTM_EMBEDDING_TIMEOUT Embedding timeout seconds (default: 120)
|
|
66
|
+
HTM_TAG_TIMEOUT Tag timeout seconds (default: 180)
|
|
67
|
+
HTM_CONNECTION_TIMEOUT Connection timeout seconds (default: 30)
|
|
68
|
+
|
|
69
|
+
Chunking:
|
|
70
|
+
HTM_CHUNK_SIZE Max chars per chunk (default: 1024)
|
|
71
|
+
HTM_CHUNK_OVERLAP Chunk overlap chars (default: 64)
|
|
72
|
+
|
|
73
|
+
Other:
|
|
74
|
+
HTM_LOG_LEVEL Log level (default: INFO)
|
|
75
|
+
HTM_JOB_BACKEND Job backend: inline, thread, active_job, sidekiq
|
|
76
|
+
HTM_TELEMETRY_ENABLED Enable OpenTelemetry (default: false)
|
|
77
|
+
HTM_MAX_EMBEDDING_DIMENSION Max vector dimensions (default: 2000)
|
|
78
|
+
HTM_MAX_TAG_DEPTH Max tag hierarchy depth (default: 4)
|
|
79
|
+
|
|
80
|
+
EXAMPLES:
|
|
81
|
+
# First-time setup
|
|
82
|
+
export HTM_DBURL="postgresql://postgres@localhost:5432/htm"
|
|
83
|
+
htm_mcp setup
|
|
84
|
+
|
|
85
|
+
# Verify connection
|
|
86
|
+
htm_mcp verify
|
|
87
|
+
|
|
88
|
+
# Use test database
|
|
89
|
+
HTM_ENV=test htm_mcp setup
|
|
90
|
+
HTM_ENV=test htm_mcp stats
|
|
91
|
+
|
|
92
|
+
# Start MCP server (for Claude Desktop)
|
|
93
|
+
htm_mcp
|
|
94
|
+
|
|
95
|
+
CLAUDE DESKTOP CONFIGURATION:
|
|
96
|
+
Add to ~/.config/claude/claude_desktop_config.json:
|
|
97
|
+
|
|
98
|
+
{
|
|
99
|
+
"mcpServers": {
|
|
100
|
+
"htm-memory": {
|
|
101
|
+
"command": "/path/to/htm_mcp",
|
|
102
|
+
"env": {
|
|
103
|
+
"HTM_DBURL": "postgresql://postgres@localhost:5432/htm_development"
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
HELP
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def check_database_config!
|
|
112
|
+
unless ENV['HTM_DBURL'] || ENV['HTM_DBNAME']
|
|
113
|
+
warn "Error: Database not configured."
|
|
114
|
+
warn "Set HTM_DBURL or HTM_DBNAME environment variable."
|
|
115
|
+
warn "Run 'htm_mcp help' for details."
|
|
116
|
+
exit 1
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def print_error_suggestion(error_message)
|
|
121
|
+
msg = error_message.to_s.downcase
|
|
122
|
+
|
|
123
|
+
warn ""
|
|
124
|
+
if msg.include?("does not exist")
|
|
125
|
+
warn "Suggestion: The database does not exist. Create it with:"
|
|
126
|
+
warn " createdb #{extract_dbname(ENV['HTM_DBURL'] || ENV['HTM_DBNAME'])}"
|
|
127
|
+
warn "Then initialize the schema with:"
|
|
128
|
+
warn " htm_mcp setup"
|
|
129
|
+
elsif msg.include?("password authentication failed") || msg.include?("no password supplied")
|
|
130
|
+
warn "Suggestion: Check your database credentials."
|
|
131
|
+
warn "Verify HTM_DBURL has correct username and password:"
|
|
132
|
+
warn " postgresql://USER:PASSWORD@localhost:5432/DATABASE"
|
|
133
|
+
elsif msg.include?("connection refused") || msg.include?("could not connect")
|
|
134
|
+
warn "Suggestion: PostgreSQL server is not running or not accepting connections."
|
|
135
|
+
warn "Start PostgreSQL with:"
|
|
136
|
+
warn " brew services start postgresql@17 # macOS with Homebrew"
|
|
137
|
+
warn " sudo systemctl start postgresql # Linux"
|
|
138
|
+
elsif msg.include?("role") && msg.include?("does not exist")
|
|
139
|
+
warn "Suggestion: The database user does not exist. Create it with:"
|
|
140
|
+
warn " createuser -s YOUR_USERNAME"
|
|
141
|
+
elsif msg.include?("permission denied")
|
|
142
|
+
warn "Suggestion: The user lacks permission to access this database."
|
|
143
|
+
warn "Grant access or use a different user with appropriate privileges."
|
|
144
|
+
elsif msg.include?("timeout") || msg.include?("timed out")
|
|
145
|
+
warn "Suggestion: Connection timed out. Check:"
|
|
146
|
+
warn " - PostgreSQL is running"
|
|
147
|
+
warn " - Firewall allows connections on port 5432"
|
|
148
|
+
warn " - Host address is correct"
|
|
149
|
+
elsif msg.include?("extension") && msg.include?("vector")
|
|
150
|
+
warn "Suggestion: pgvector extension is not installed. Install it with:"
|
|
151
|
+
warn " brew install pgvector # macOS"
|
|
152
|
+
warn "Then enable it in your database:"
|
|
153
|
+
warn " psql -d DATABASE -c 'CREATE EXTENSION vector;'"
|
|
154
|
+
else
|
|
155
|
+
warn "Suggestion: Run 'htm_mcp help' for configuration details."
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def extract_dbname(url_or_name)
|
|
160
|
+
return url_or_name unless url_or_name&.include?("://")
|
|
161
|
+
|
|
162
|
+
# Extract database name from URL like postgresql://user@host:port/dbname
|
|
163
|
+
if url_or_name =~ %r{/([^/?]+)(?:\?|$)}
|
|
164
|
+
$1
|
|
165
|
+
else
|
|
166
|
+
"htm_development"
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
def run_setup
|
|
171
|
+
puts "HTM Database Setup"
|
|
172
|
+
puts "=================="
|
|
173
|
+
puts
|
|
174
|
+
|
|
175
|
+
check_database_config!
|
|
176
|
+
|
|
177
|
+
begin
|
|
178
|
+
HTM::Database.setup
|
|
179
|
+
puts
|
|
180
|
+
puts "Database initialized successfully!"
|
|
181
|
+
puts "You can now start the MCP server with: htm_mcp"
|
|
182
|
+
rescue => e
|
|
183
|
+
warn "Setup failed: #{e.message}"
|
|
184
|
+
print_error_suggestion(e.message)
|
|
185
|
+
warn e.backtrace.first(5).join("\n") if ENV['DEBUG']
|
|
186
|
+
exit 1
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
def run_verify
|
|
191
|
+
puts "HTM Database Verification"
|
|
192
|
+
puts "========================="
|
|
193
|
+
puts
|
|
194
|
+
|
|
195
|
+
check_database_config!
|
|
196
|
+
|
|
197
|
+
begin
|
|
198
|
+
HTM::Database.info
|
|
199
|
+
puts
|
|
200
|
+
|
|
201
|
+
# Check migration status
|
|
202
|
+
pending = check_migration_status
|
|
203
|
+
puts
|
|
204
|
+
|
|
205
|
+
if pending > 0
|
|
206
|
+
warn "Warning: #{pending} pending migration(s) detected."
|
|
207
|
+
warn " Run 'htm_mcp setup' to apply pending migrations."
|
|
208
|
+
puts
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
puts "Database connection verified!"
|
|
212
|
+
rescue => e
|
|
213
|
+
warn "Verification failed: #{e.message}"
|
|
214
|
+
print_error_suggestion(e.message)
|
|
215
|
+
warn e.backtrace.first(5).join("\n") if ENV['DEBUG']
|
|
216
|
+
exit 1
|
|
217
|
+
end
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
def check_migration_status
|
|
221
|
+
migrations_path = File.expand_path('../../../db/migrate', __dir__)
|
|
222
|
+
|
|
223
|
+
# Get available migrations from files
|
|
224
|
+
available_migrations = Dir.glob(File.join(migrations_path, '*.rb')).map do |file|
|
|
225
|
+
{
|
|
226
|
+
version: File.basename(file).split('_').first,
|
|
227
|
+
name: File.basename(file, '.rb')
|
|
228
|
+
}
|
|
229
|
+
end.sort_by { |m| m[:version] }
|
|
230
|
+
|
|
231
|
+
# Ensure ActiveRecord connection for migration check
|
|
232
|
+
HTM::ActiveRecordConfig.establish_connection!
|
|
233
|
+
|
|
234
|
+
# Get applied migrations from database
|
|
235
|
+
applied_versions = begin
|
|
236
|
+
ActiveRecord::Base.connection.select_values('SELECT version FROM schema_migrations ORDER BY version')
|
|
237
|
+
rescue ActiveRecord::StatementInvalid
|
|
238
|
+
[]
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
puts "Migration Status"
|
|
242
|
+
puts "-" * 80
|
|
243
|
+
|
|
244
|
+
if available_migrations.empty?
|
|
245
|
+
puts " No migration files found"
|
|
246
|
+
return 0
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
available_migrations.each do |migration|
|
|
250
|
+
applied = applied_versions.include?(migration[:version])
|
|
251
|
+
status_mark = applied ? "+" : "-"
|
|
252
|
+
puts " #{status_mark} #{migration[:name]}"
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
applied_count = applied_versions.length
|
|
256
|
+
pending_count = available_migrations.length - applied_count
|
|
257
|
+
|
|
258
|
+
puts "-" * 80
|
|
259
|
+
puts " #{applied_count} applied, #{pending_count} pending"
|
|
260
|
+
|
|
261
|
+
pending_count
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
def run_stats
|
|
265
|
+
puts "HTM Memory Statistics"
|
|
266
|
+
puts "====================="
|
|
267
|
+
puts
|
|
268
|
+
|
|
269
|
+
check_database_config!
|
|
270
|
+
|
|
271
|
+
begin
|
|
272
|
+
HTM::ActiveRecordConfig.establish_connection!
|
|
273
|
+
|
|
274
|
+
total_nodes = HTM::Models::Node.count
|
|
275
|
+
deleted_nodes = HTM::Models::Node.deleted.count
|
|
276
|
+
with_embeddings = HTM::Models::Node.with_embeddings.count
|
|
277
|
+
total_tags = HTM::Models::Tag.count
|
|
278
|
+
total_robots = HTM::Models::Robot.count
|
|
279
|
+
total_files = HTM::Models::FileSource.count
|
|
280
|
+
|
|
281
|
+
# Get database size
|
|
282
|
+
db_size = ActiveRecord::Base.connection.execute(
|
|
283
|
+
"SELECT pg_size_pretty(pg_database_size(current_database())) AS size"
|
|
284
|
+
).first['size']
|
|
285
|
+
|
|
286
|
+
puts "Nodes: #{total_nodes} active, #{deleted_nodes} deleted, #{with_embeddings} with embeddings"
|
|
287
|
+
puts "Tags: #{total_tags}"
|
|
288
|
+
puts "Robots: #{total_robots}"
|
|
289
|
+
puts "Files: #{total_files}"
|
|
290
|
+
puts
|
|
291
|
+
puts "Database size: #{db_size}"
|
|
292
|
+
rescue => e
|
|
293
|
+
warn "Stats failed: #{e.message}"
|
|
294
|
+
print_error_suggestion(e.message)
|
|
295
|
+
warn e.backtrace.first(5).join("\n") if ENV['DEBUG']
|
|
296
|
+
exit 1
|
|
297
|
+
end
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
def run(args)
|
|
301
|
+
case args[0]&.downcase
|
|
302
|
+
when 'help', '-h', '--help'
|
|
303
|
+
print_help
|
|
304
|
+
exit 0
|
|
305
|
+
when 'version', '-v', '--version'
|
|
306
|
+
puts "HTM #{HTM::VERSION}"
|
|
307
|
+
exit 0
|
|
308
|
+
when 'setup', 'init'
|
|
309
|
+
run_setup
|
|
310
|
+
exit 0
|
|
311
|
+
when 'verify'
|
|
312
|
+
run_verify
|
|
313
|
+
exit 0
|
|
314
|
+
when 'stats'
|
|
315
|
+
run_stats
|
|
316
|
+
exit 0
|
|
317
|
+
when 'server', 'stdio', nil
|
|
318
|
+
# Return false to indicate server should start
|
|
319
|
+
# 'stdio' is accepted for compatibility with MCP clients that pass it as an argument
|
|
320
|
+
false
|
|
321
|
+
when /^-/
|
|
322
|
+
warn "Unknown option: #{args[0]}"
|
|
323
|
+
warn "Run 'htm_mcp help' for usage."
|
|
324
|
+
exit 1
|
|
325
|
+
else
|
|
326
|
+
warn "Unknown command: #{args[0]}"
|
|
327
|
+
warn "Run 'htm_mcp help' for usage."
|
|
328
|
+
exit 1
|
|
329
|
+
end
|
|
330
|
+
end
|
|
331
|
+
end
|
|
332
|
+
end
|
|
333
|
+
end
|