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.
Files changed (75) hide show
  1. checksums.yaml +4 -4
  2. data/.envrc +1 -0
  3. data/CHANGELOG.md +67 -0
  4. data/README.md +97 -1592
  5. data/bin/htm_mcp +31 -0
  6. data/config/database.yml +7 -4
  7. data/docs/getting-started/installation.md +31 -11
  8. data/docs/guides/mcp-server.md +456 -21
  9. data/docs/multi_framework_support.md +2 -2
  10. data/examples/mcp_client.rb +2 -2
  11. data/examples/rails_app/.gitignore +2 -0
  12. data/examples/rails_app/Gemfile +22 -0
  13. data/examples/rails_app/Gemfile.lock +438 -0
  14. data/examples/rails_app/Procfile.dev +1 -0
  15. data/examples/rails_app/README.md +98 -0
  16. data/examples/rails_app/Rakefile +5 -0
  17. data/examples/rails_app/app/assets/stylesheets/application.css +83 -0
  18. data/examples/rails_app/app/assets/stylesheets/inter-font.css +6 -0
  19. data/examples/rails_app/app/controllers/application_controller.rb +19 -0
  20. data/examples/rails_app/app/controllers/dashboard_controller.rb +27 -0
  21. data/examples/rails_app/app/controllers/files_controller.rb +205 -0
  22. data/examples/rails_app/app/controllers/memories_controller.rb +102 -0
  23. data/examples/rails_app/app/controllers/robots_controller.rb +44 -0
  24. data/examples/rails_app/app/controllers/search_controller.rb +46 -0
  25. data/examples/rails_app/app/controllers/tags_controller.rb +30 -0
  26. data/examples/rails_app/app/javascript/application.js +4 -0
  27. data/examples/rails_app/app/javascript/controllers/application.js +9 -0
  28. data/examples/rails_app/app/javascript/controllers/index.js +6 -0
  29. data/examples/rails_app/app/views/dashboard/index.html.erb +123 -0
  30. data/examples/rails_app/app/views/files/index.html.erb +108 -0
  31. data/examples/rails_app/app/views/files/new.html.erb +321 -0
  32. data/examples/rails_app/app/views/files/show.html.erb +130 -0
  33. data/examples/rails_app/app/views/layouts/application.html.erb +124 -0
  34. data/examples/rails_app/app/views/memories/_memory_card.html.erb +51 -0
  35. data/examples/rails_app/app/views/memories/deleted.html.erb +62 -0
  36. data/examples/rails_app/app/views/memories/edit.html.erb +35 -0
  37. data/examples/rails_app/app/views/memories/index.html.erb +81 -0
  38. data/examples/rails_app/app/views/memories/new.html.erb +71 -0
  39. data/examples/rails_app/app/views/memories/show.html.erb +126 -0
  40. data/examples/rails_app/app/views/robots/index.html.erb +106 -0
  41. data/examples/rails_app/app/views/robots/new.html.erb +36 -0
  42. data/examples/rails_app/app/views/robots/show.html.erb +79 -0
  43. data/examples/rails_app/app/views/search/index.html.erb +184 -0
  44. data/examples/rails_app/app/views/shared/_navbar.html.erb +52 -0
  45. data/examples/rails_app/app/views/shared/_stat_card.html.erb +52 -0
  46. data/examples/rails_app/app/views/tags/index.html.erb +131 -0
  47. data/examples/rails_app/app/views/tags/show.html.erb +67 -0
  48. data/examples/rails_app/bin/dev +8 -0
  49. data/examples/rails_app/bin/rails +4 -0
  50. data/examples/rails_app/bin/rake +4 -0
  51. data/examples/rails_app/config/application.rb +33 -0
  52. data/examples/rails_app/config/boot.rb +5 -0
  53. data/examples/rails_app/config/database.yml +15 -0
  54. data/examples/rails_app/config/environment.rb +5 -0
  55. data/examples/rails_app/config/importmap.rb +7 -0
  56. data/examples/rails_app/config/routes.rb +38 -0
  57. data/examples/rails_app/config/tailwind.config.js +35 -0
  58. data/examples/rails_app/config.ru +5 -0
  59. data/examples/rails_app/log/.keep +0 -0
  60. data/examples/rails_app/tmp/local_secret.txt +1 -0
  61. data/lib/htm/active_record_config.rb +2 -5
  62. data/lib/htm/configuration.rb +35 -2
  63. data/lib/htm/database.rb +3 -6
  64. data/lib/htm/mcp/cli.rb +333 -0
  65. data/lib/htm/mcp/group_tools.rb +476 -0
  66. data/lib/htm/mcp/resources.rb +89 -0
  67. data/lib/htm/mcp/server.rb +98 -0
  68. data/lib/htm/mcp/tools.rb +488 -0
  69. data/lib/htm/models/file_source.rb +5 -3
  70. data/lib/htm/railtie.rb +0 -4
  71. data/lib/htm/tasks.rb +7 -4
  72. data/lib/htm/version.rb +1 -1
  73. data/lib/tasks/htm.rake +6 -9
  74. metadata +59 -4
  75. data/bin/htm_mcp.rb +0 -621
@@ -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