spatial-memory-mcp 1.6.1__py3-none-any.whl

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.

Potentially problematic release.


This version of spatial-memory-mcp might be problematic. Click here for more details.

Files changed (54) hide show
  1. spatial_memory/__init__.py +97 -0
  2. spatial_memory/__main__.py +270 -0
  3. spatial_memory/adapters/__init__.py +7 -0
  4. spatial_memory/adapters/lancedb_repository.py +878 -0
  5. spatial_memory/config.py +728 -0
  6. spatial_memory/core/__init__.py +118 -0
  7. spatial_memory/core/cache.py +317 -0
  8. spatial_memory/core/circuit_breaker.py +297 -0
  9. spatial_memory/core/connection_pool.py +220 -0
  10. spatial_memory/core/consolidation_strategies.py +402 -0
  11. spatial_memory/core/database.py +3069 -0
  12. spatial_memory/core/db_idempotency.py +242 -0
  13. spatial_memory/core/db_indexes.py +575 -0
  14. spatial_memory/core/db_migrations.py +584 -0
  15. spatial_memory/core/db_search.py +509 -0
  16. spatial_memory/core/db_versioning.py +177 -0
  17. spatial_memory/core/embeddings.py +557 -0
  18. spatial_memory/core/errors.py +317 -0
  19. spatial_memory/core/file_security.py +702 -0
  20. spatial_memory/core/filesystem.py +178 -0
  21. spatial_memory/core/health.py +289 -0
  22. spatial_memory/core/helpers.py +79 -0
  23. spatial_memory/core/import_security.py +432 -0
  24. spatial_memory/core/lifecycle_ops.py +1067 -0
  25. spatial_memory/core/logging.py +194 -0
  26. spatial_memory/core/metrics.py +192 -0
  27. spatial_memory/core/models.py +628 -0
  28. spatial_memory/core/rate_limiter.py +326 -0
  29. spatial_memory/core/response_types.py +497 -0
  30. spatial_memory/core/security.py +588 -0
  31. spatial_memory/core/spatial_ops.py +426 -0
  32. spatial_memory/core/tracing.py +300 -0
  33. spatial_memory/core/utils.py +110 -0
  34. spatial_memory/core/validation.py +403 -0
  35. spatial_memory/factory.py +407 -0
  36. spatial_memory/migrations/__init__.py +40 -0
  37. spatial_memory/ports/__init__.py +11 -0
  38. spatial_memory/ports/repositories.py +631 -0
  39. spatial_memory/py.typed +0 -0
  40. spatial_memory/server.py +1141 -0
  41. spatial_memory/services/__init__.py +70 -0
  42. spatial_memory/services/export_import.py +1023 -0
  43. spatial_memory/services/lifecycle.py +1120 -0
  44. spatial_memory/services/memory.py +412 -0
  45. spatial_memory/services/spatial.py +1147 -0
  46. spatial_memory/services/utility.py +409 -0
  47. spatial_memory/tools/__init__.py +5 -0
  48. spatial_memory/tools/definitions.py +695 -0
  49. spatial_memory/verify.py +140 -0
  50. spatial_memory_mcp-1.6.1.dist-info/METADATA +499 -0
  51. spatial_memory_mcp-1.6.1.dist-info/RECORD +54 -0
  52. spatial_memory_mcp-1.6.1.dist-info/WHEEL +4 -0
  53. spatial_memory_mcp-1.6.1.dist-info/entry_points.txt +2 -0
  54. spatial_memory_mcp-1.6.1.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,407 @@
1
+ """Service factory for dependency injection and initialization.
2
+
3
+ This module provides a factory pattern for creating and wiring all services
4
+ used by the SpatialMemoryServer. It centralizes configuration and dependency
5
+ injection, making the server initialization cleaner and services more testable.
6
+
7
+ Usage:
8
+ from spatial_memory.factory import ServiceFactory
9
+
10
+ factory = ServiceFactory(settings)
11
+ services = factory.create_all()
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ import logging
17
+ from dataclasses import dataclass
18
+ from typing import TYPE_CHECKING
19
+
20
+ from spatial_memory.adapters.lancedb_repository import LanceDBMemoryRepository
21
+ from spatial_memory.config import Settings
22
+ from spatial_memory.core.cache import ResponseCache
23
+ from spatial_memory.core.database import Database
24
+ from spatial_memory.core.embeddings import EmbeddingService
25
+ from spatial_memory.core.rate_limiter import AgentAwareRateLimiter, RateLimiter
26
+ from spatial_memory.services.export_import import ExportImportConfig, ExportImportService
27
+ from spatial_memory.services.lifecycle import LifecycleConfig, LifecycleService
28
+ from spatial_memory.services.memory import MemoryService
29
+ from spatial_memory.services.spatial import SpatialConfig, SpatialService
30
+ from spatial_memory.services.utility import UtilityConfig, UtilityService
31
+
32
+ if TYPE_CHECKING:
33
+ from spatial_memory.ports.repositories import (
34
+ EmbeddingServiceProtocol,
35
+ MemoryRepositoryProtocol,
36
+ )
37
+
38
+ logger = logging.getLogger(__name__)
39
+
40
+
41
+ @dataclass
42
+ class ServiceContainer:
43
+ """Container for all initialized services.
44
+
45
+ Provides access to all service instances created by the factory.
46
+ This allows the server to access services through a single container
47
+ rather than managing individual references.
48
+
49
+ Attributes:
50
+ embeddings: Embedding service for vector generation.
51
+ database: Database connection and operations.
52
+ repository: Memory repository for CRUD operations.
53
+ memory: Memory service for remember/recall operations.
54
+ spatial: Spatial service for exploration operations.
55
+ lifecycle: Lifecycle service for decay/reinforce/consolidate.
56
+ utility: Utility service for stats/namespaces/hybrid search.
57
+ export_import: Export/import service for data portability.
58
+ rate_limiter: Simple rate limiter (if per-agent disabled).
59
+ agent_rate_limiter: Per-agent rate limiter (if enabled).
60
+ cache: Response cache for read operations.
61
+ per_agent_rate_limiting: Whether per-agent rate limiting is enabled.
62
+ cache_enabled: Whether response caching is enabled.
63
+ regions_cache_ttl: TTL for regions cache entries.
64
+ """
65
+
66
+ embeddings: EmbeddingServiceProtocol
67
+ database: Database | None
68
+ repository: MemoryRepositoryProtocol
69
+ memory: MemoryService
70
+ spatial: SpatialService
71
+ lifecycle: LifecycleService
72
+ utility: UtilityService
73
+ export_import: ExportImportService
74
+ rate_limiter: RateLimiter | None
75
+ agent_rate_limiter: AgentAwareRateLimiter | None
76
+ cache: ResponseCache | None
77
+ per_agent_rate_limiting: bool
78
+ cache_enabled: bool
79
+ regions_cache_ttl: float
80
+
81
+
82
+ class ServiceFactory:
83
+ """Factory for creating and wiring all services.
84
+
85
+ Centralizes service creation with proper dependency injection.
86
+ This simplifies server initialization and improves testability.
87
+
88
+ Example:
89
+ factory = ServiceFactory(settings)
90
+ services = factory.create_all()
91
+ # Use services.memory, services.spatial, etc.
92
+ """
93
+
94
+ def __init__(
95
+ self,
96
+ settings: Settings,
97
+ repository: MemoryRepositoryProtocol | None = None,
98
+ embeddings: EmbeddingServiceProtocol | None = None,
99
+ ) -> None:
100
+ """Initialize the factory.
101
+
102
+ Args:
103
+ settings: Application settings.
104
+ repository: Optional repository override for testing.
105
+ embeddings: Optional embeddings override for testing.
106
+ """
107
+ self._settings = settings
108
+ self._injected_repository = repository
109
+ self._injected_embeddings = embeddings
110
+
111
+ def create_embedding_service(self) -> EmbeddingService:
112
+ """Create the embedding service.
113
+
114
+ Returns:
115
+ Configured EmbeddingService instance.
116
+ """
117
+ return EmbeddingService(
118
+ model_name=self._settings.embedding_model,
119
+ openai_api_key=self._settings.openai_api_key,
120
+ backend=self._settings.embedding_backend, # type: ignore[arg-type]
121
+ )
122
+
123
+ def create_database(self, embedding_dim: int) -> Database:
124
+ """Create the database connection.
125
+
126
+ Args:
127
+ embedding_dim: Dimension of embedding vectors.
128
+
129
+ Returns:
130
+ Configured Database instance.
131
+ """
132
+ db = Database(
133
+ storage_path=self._settings.memory_path,
134
+ embedding_dim=embedding_dim,
135
+ auto_create_indexes=self._settings.auto_create_indexes,
136
+ vector_index_threshold=self._settings.vector_index_threshold,
137
+ enable_fts=self._settings.enable_fts_index,
138
+ index_nprobes=self._settings.index_nprobes,
139
+ index_refine_factor=self._settings.index_refine_factor,
140
+ max_retry_attempts=self._settings.max_retry_attempts,
141
+ retry_backoff_seconds=self._settings.retry_backoff_seconds,
142
+ read_consistency_interval_ms=self._settings.read_consistency_interval_ms,
143
+ index_wait_timeout_seconds=self._settings.index_wait_timeout_seconds,
144
+ fts_stem=self._settings.fts_stem,
145
+ fts_remove_stop_words=self._settings.fts_remove_stop_words,
146
+ fts_language=self._settings.fts_language,
147
+ index_type=self._settings.index_type,
148
+ hnsw_m=self._settings.hnsw_m,
149
+ hnsw_ef_construction=self._settings.hnsw_ef_construction,
150
+ enable_memory_expiration=self._settings.enable_memory_expiration,
151
+ default_memory_ttl_days=self._settings.default_memory_ttl_days,
152
+ acknowledge_network_filesystem_risk=self._settings.acknowledge_network_filesystem_risk,
153
+ )
154
+ db.connect()
155
+ return db
156
+
157
+ def create_repository(self, database: Database) -> LanceDBMemoryRepository:
158
+ """Create the memory repository.
159
+
160
+ Args:
161
+ database: Database instance.
162
+
163
+ Returns:
164
+ LanceDBMemoryRepository instance.
165
+ """
166
+ return LanceDBMemoryRepository(database)
167
+
168
+ def create_memory_service(
169
+ self,
170
+ repository: MemoryRepositoryProtocol,
171
+ embeddings: EmbeddingServiceProtocol,
172
+ ) -> MemoryService:
173
+ """Create the memory service.
174
+
175
+ Args:
176
+ repository: Memory repository.
177
+ embeddings: Embedding service.
178
+
179
+ Returns:
180
+ Configured MemoryService instance.
181
+ """
182
+ return MemoryService(
183
+ repository=repository,
184
+ embeddings=embeddings,
185
+ )
186
+
187
+ def create_spatial_service(
188
+ self,
189
+ repository: MemoryRepositoryProtocol,
190
+ embeddings: EmbeddingServiceProtocol,
191
+ ) -> SpatialService:
192
+ """Create the spatial service.
193
+
194
+ Args:
195
+ repository: Memory repository.
196
+ embeddings: Embedding service.
197
+
198
+ Returns:
199
+ Configured SpatialService instance.
200
+ """
201
+ return SpatialService(
202
+ repository=repository,
203
+ embeddings=embeddings,
204
+ config=SpatialConfig(
205
+ journey_max_steps=self._settings.max_journey_steps,
206
+ wander_max_steps=self._settings.max_wander_steps,
207
+ regions_max_memories=self._settings.regions_max_memories,
208
+ visualize_max_memories=self._settings.max_visualize_memories,
209
+ visualize_n_neighbors=self._settings.umap_n_neighbors,
210
+ visualize_min_dist=self._settings.umap_min_dist,
211
+ visualize_similarity_threshold=self._settings.visualize_similarity_threshold,
212
+ ),
213
+ )
214
+
215
+ def create_lifecycle_service(
216
+ self,
217
+ repository: MemoryRepositoryProtocol,
218
+ embeddings: EmbeddingServiceProtocol,
219
+ ) -> LifecycleService:
220
+ """Create the lifecycle service.
221
+
222
+ Args:
223
+ repository: Memory repository.
224
+ embeddings: Embedding service.
225
+
226
+ Returns:
227
+ Configured LifecycleService instance.
228
+ """
229
+ return LifecycleService(
230
+ repository=repository,
231
+ embeddings=embeddings,
232
+ config=LifecycleConfig(
233
+ decay_default_half_life_days=self._settings.decay_default_half_life_days,
234
+ decay_default_function=self._settings.decay_default_function,
235
+ decay_min_importance_floor=self._settings.decay_min_importance_floor,
236
+ decay_batch_size=self._settings.decay_batch_size,
237
+ reinforce_default_boost=self._settings.reinforce_default_boost,
238
+ reinforce_max_importance=self._settings.reinforce_max_importance,
239
+ extract_max_text_length=self._settings.extract_max_text_length,
240
+ extract_max_candidates=self._settings.extract_max_candidates,
241
+ extract_default_importance=self._settings.extract_default_importance,
242
+ extract_default_namespace=self._settings.extract_default_namespace,
243
+ consolidate_min_threshold=self._settings.consolidate_min_threshold,
244
+ consolidate_content_weight=self._settings.consolidate_content_weight,
245
+ consolidate_max_batch=self._settings.consolidate_max_batch,
246
+ ),
247
+ )
248
+
249
+ def create_utility_service(
250
+ self,
251
+ repository: MemoryRepositoryProtocol,
252
+ embeddings: EmbeddingServiceProtocol,
253
+ ) -> UtilityService:
254
+ """Create the utility service.
255
+
256
+ Args:
257
+ repository: Memory repository.
258
+ embeddings: Embedding service.
259
+
260
+ Returns:
261
+ Configured UtilityService instance.
262
+ """
263
+ return UtilityService(
264
+ repository=repository,
265
+ embeddings=embeddings,
266
+ config=UtilityConfig(
267
+ hybrid_default_alpha=self._settings.hybrid_default_alpha,
268
+ hybrid_min_alpha=self._settings.hybrid_min_alpha,
269
+ hybrid_max_alpha=self._settings.hybrid_max_alpha,
270
+ stats_include_index_details=True,
271
+ namespace_batch_size=self._settings.namespace_batch_size,
272
+ delete_namespace_require_confirmation=self._settings.destructive_require_namespace_confirmation,
273
+ ),
274
+ )
275
+
276
+ def create_export_import_service(
277
+ self,
278
+ repository: MemoryRepositoryProtocol,
279
+ embeddings: EmbeddingServiceProtocol,
280
+ ) -> ExportImportService:
281
+ """Create the export/import service.
282
+
283
+ Args:
284
+ repository: Memory repository.
285
+ embeddings: Embedding service.
286
+
287
+ Returns:
288
+ Configured ExportImportService instance.
289
+ """
290
+ return ExportImportService(
291
+ repository=repository,
292
+ embeddings=embeddings,
293
+ config=ExportImportConfig(
294
+ default_export_format=self._settings.export_default_format,
295
+ export_batch_size=self._settings.export_batch_size,
296
+ import_batch_size=self._settings.import_batch_size,
297
+ import_deduplicate=self._settings.import_deduplicate_default,
298
+ import_dedup_threshold=self._settings.import_dedup_threshold,
299
+ validate_on_import=self._settings.import_validate_vectors,
300
+ parquet_compression="zstd",
301
+ max_import_records=self._settings.import_max_records,
302
+ csv_include_vectors=self._settings.csv_include_vectors,
303
+ max_export_records=self._settings.max_export_records,
304
+ ),
305
+ allowed_export_paths=self._settings.export_allowed_paths,
306
+ allowed_import_paths=self._settings.import_allowed_paths,
307
+ allow_symlinks=self._settings.export_allow_symlinks,
308
+ max_import_size_bytes=int(self._settings.import_max_file_size_mb * 1024 * 1024),
309
+ )
310
+
311
+ def create_rate_limiter(self) -> tuple[RateLimiter | None, AgentAwareRateLimiter | None, bool]:
312
+ """Create rate limiter based on settings.
313
+
314
+ Returns:
315
+ Tuple of (simple_limiter, agent_limiter, per_agent_enabled).
316
+ """
317
+ per_agent = self._settings.rate_limit_per_agent_enabled
318
+ if per_agent:
319
+ return (
320
+ None,
321
+ AgentAwareRateLimiter(
322
+ global_rate=self._settings.embedding_rate_limit,
323
+ per_agent_rate=self._settings.rate_limit_per_agent_rate,
324
+ max_agents=self._settings.rate_limit_max_tracked_agents,
325
+ ),
326
+ True,
327
+ )
328
+ return (
329
+ RateLimiter(
330
+ rate=self._settings.embedding_rate_limit,
331
+ capacity=int(self._settings.embedding_rate_limit * 2),
332
+ ),
333
+ None,
334
+ False,
335
+ )
336
+
337
+ def create_cache(self) -> tuple[ResponseCache | None, bool, float]:
338
+ """Create response cache based on settings.
339
+
340
+ Returns:
341
+ Tuple of (cache, enabled, regions_ttl).
342
+ """
343
+ if not self._settings.response_cache_enabled:
344
+ return None, False, 0.0
345
+ return (
346
+ ResponseCache(
347
+ max_size=self._settings.response_cache_max_size,
348
+ default_ttl=self._settings.response_cache_default_ttl,
349
+ ),
350
+ True,
351
+ self._settings.response_cache_regions_ttl,
352
+ )
353
+
354
+ def create_all(self) -> ServiceContainer:
355
+ """Create all services with proper dependency wiring.
356
+
357
+ Returns:
358
+ ServiceContainer with all services initialized.
359
+ """
360
+ # Use injected dependencies or create new ones
361
+ if self._injected_embeddings is None:
362
+ embeddings = self.create_embedding_service()
363
+ else:
364
+ embeddings = self._injected_embeddings
365
+
366
+ # Auto-detect embedding dimensions
367
+ embedding_dim = embeddings.dimensions
368
+ logger.info(f"Auto-detected embedding dimensions: {embedding_dim}")
369
+ logger.info(f"Embedding backend: {embeddings.backend}")
370
+
371
+ # Create database and repository
372
+ database: Database | None = None
373
+ if self._injected_repository is None:
374
+ database = self.create_database(embedding_dim)
375
+ repository = self.create_repository(database)
376
+ else:
377
+ repository = self._injected_repository
378
+
379
+ # Create services with shared dependencies
380
+ memory = self.create_memory_service(repository, embeddings)
381
+ spatial = self.create_spatial_service(repository, embeddings)
382
+ lifecycle = self.create_lifecycle_service(repository, embeddings)
383
+ utility = self.create_utility_service(repository, embeddings)
384
+ export_import = self.create_export_import_service(repository, embeddings)
385
+
386
+ # Create rate limiter
387
+ rate_limiter, agent_rate_limiter, per_agent_enabled = self.create_rate_limiter()
388
+
389
+ # Create cache
390
+ cache, cache_enabled, regions_cache_ttl = self.create_cache()
391
+
392
+ return ServiceContainer(
393
+ embeddings=embeddings,
394
+ database=database,
395
+ repository=repository,
396
+ memory=memory,
397
+ spatial=spatial,
398
+ lifecycle=lifecycle,
399
+ utility=utility,
400
+ export_import=export_import,
401
+ rate_limiter=rate_limiter,
402
+ agent_rate_limiter=agent_rate_limiter,
403
+ cache=cache,
404
+ per_agent_rate_limiting=per_agent_enabled,
405
+ cache_enabled=cache_enabled,
406
+ regions_cache_ttl=regions_cache_ttl,
407
+ )
@@ -0,0 +1,40 @@
1
+ """Database migrations for spatial-memory-mcp.
2
+
3
+ This package contains database migration scripts for schema changes.
4
+ Each migration is a module that exports a Migration class.
5
+
6
+ Migrations should be numbered sequentially (001, 002, etc.) and use
7
+ semantic versioning for their version string.
8
+
9
+ Example:
10
+ # migrations/001_add_expires_at.py
11
+ from spatial_memory.core.db_migrations import Migration
12
+
13
+ class Migration001AddExpiresAt(Migration):
14
+ version = "1.1.0"
15
+ description = "Add expires_at column for TTL support"
16
+
17
+ def up(self, db, embeddings=None):
18
+ # Apply migration
19
+ pass
20
+
21
+ def down(self, db):
22
+ # Rollback migration (optional)
23
+ raise NotImplementedError("Rollback not supported")
24
+ """
25
+
26
+ from spatial_memory.core.db_migrations import (
27
+ CURRENT_SCHEMA_VERSION,
28
+ Migration,
29
+ MigrationManager,
30
+ MigrationResult,
31
+ check_migration_status,
32
+ )
33
+
34
+ __all__ = [
35
+ "CURRENT_SCHEMA_VERSION",
36
+ "Migration",
37
+ "MigrationManager",
38
+ "MigrationResult",
39
+ "check_migration_status",
40
+ ]
@@ -0,0 +1,11 @@
1
+ """Port interfaces for Spatial Memory MCP Server."""
2
+
3
+ from spatial_memory.ports.repositories import (
4
+ EmbeddingServiceProtocol,
5
+ MemoryRepositoryProtocol,
6
+ )
7
+
8
+ __all__ = [
9
+ "EmbeddingServiceProtocol",
10
+ "MemoryRepositoryProtocol",
11
+ ]