spatial-memory-mcp 1.6.0__py3-none-any.whl → 1.6.2__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.

@@ -1,6 +1,6 @@
1
1
  """Spatial Memory MCP Server - Vector-based semantic memory for LLMs."""
2
2
 
3
- __version__ = "1.6.0"
3
+ __version__ = "1.6.2"
4
4
  __author__ = "arman-tech"
5
5
 
6
6
  # Re-export core components for convenience
@@ -44,7 +44,7 @@ def run_migrate(args: argparse.Namespace) -> int:
44
44
  format="%(levelname)s: %(message)s",
45
45
  )
46
46
 
47
- print(f"Spatial Memory Migration Tool")
47
+ print("Spatial Memory Migration Tool")
48
48
  print(f"Target schema version: {CURRENT_SCHEMA_VERSION}")
49
49
  print(f"Database path: {settings.memory_path}")
50
50
  print()
@@ -109,7 +109,7 @@ def run_migrate(args: argparse.Namespace) -> int:
109
109
  return 1
110
110
 
111
111
  if result.migrations_applied:
112
- print(f"\nRolled back migrations:")
112
+ print("\nRolled back migrations:")
113
113
  for v in result.migrations_applied:
114
114
  print(f" - {v}")
115
115
  print(f"\nCurrent version: {result.current_version}")
@@ -177,6 +177,14 @@ def run_version() -> None:
177
177
  print(f"spatial-memory {__version__}")
178
178
 
179
179
 
180
+ def run_instructions() -> None:
181
+ """Print the MCP server instructions that are auto-injected into Claude's context."""
182
+ from spatial_memory.server import SpatialMemoryServer
183
+
184
+ instructions = SpatialMemoryServer._get_server_instructions()
185
+ print(instructions)
186
+
187
+
180
188
  def main() -> NoReturn:
181
189
  """Main entry point with subcommand support."""
182
190
  parser = argparse.ArgumentParser(
@@ -196,11 +204,17 @@ def main() -> NoReturn:
196
204
  )
197
205
 
198
206
  # Server command (default)
199
- server_parser = subparsers.add_parser(
207
+ subparsers.add_parser(
200
208
  "serve",
201
209
  help="Start the MCP server (default if no command given)",
202
210
  )
203
211
 
212
+ # Instructions command
213
+ subparsers.add_parser(
214
+ "instructions",
215
+ help="Show the MCP instructions injected into Claude's context",
216
+ )
217
+
204
218
  # Migrate command
205
219
  migrate_parser = subparsers.add_parser(
206
220
  "migrate",
@@ -238,7 +252,10 @@ def main() -> NoReturn:
238
252
  run_version()
239
253
  sys.exit(0)
240
254
 
241
- if args.command == "migrate":
255
+ if args.command == "instructions":
256
+ run_instructions()
257
+ sys.exit(0)
258
+ elif args.command == "migrate":
242
259
  sys.exit(run_migrate(args))
243
260
  elif args.command == "serve" or args.command is None:
244
261
  # Default to running the server
spatial_memory/config.py CHANGED
@@ -47,7 +47,7 @@ class Settings(BaseSettings):
47
47
  )
48
48
  embedding_backend: str = Field(
49
49
  default="auto",
50
- description="Embedding backend: 'auto' (ONNX if available, else PyTorch), 'onnx', or 'pytorch'",
50
+ description="Embedding backend: 'auto', 'onnx', or 'pytorch'",
51
51
  )
52
52
 
53
53
  # OpenAI (optional)
@@ -11,7 +11,6 @@ from spatial_memory.core.db_indexes import IndexManager
11
11
  from spatial_memory.core.db_search import SearchManager
12
12
  from spatial_memory.core.db_versioning import VersionManager
13
13
  from spatial_memory.core.embeddings import EmbeddingService
14
- from spatial_memory.core.rate_limiter import RateLimiter
15
14
  from spatial_memory.core.errors import (
16
15
  ClusteringError,
17
16
  ConfigurationError,
@@ -45,7 +44,7 @@ from spatial_memory.core.models import (
45
44
  VisualizationEdge,
46
45
  VisualizationNode,
47
46
  )
48
- from spatial_memory.core.utils import to_aware_utc, to_naive_utc, utc_now, utc_now_naive
47
+ from spatial_memory.core.rate_limiter import RateLimiter
49
48
  from spatial_memory.core.tracing import (
50
49
  RequestContext,
51
50
  TimingContext,
@@ -55,6 +54,7 @@ from spatial_memory.core.tracing import (
55
54
  request_context,
56
55
  set_context,
57
56
  )
57
+ from spatial_memory.core.utils import to_aware_utc, to_naive_utc, utc_now, utc_now_naive
58
58
 
59
59
  __all__ = [
60
60
  # Errors - Base
@@ -26,7 +26,6 @@ from spatial_memory.core.lifecycle_ops import (
26
26
  from spatial_memory.core.models import Memory, MemorySource
27
27
 
28
28
  if TYPE_CHECKING:
29
- import numpy as np
30
29
 
31
30
  from spatial_memory.ports.repositories import (
32
31
  EmbeddingServiceProtocol,
@@ -14,7 +14,6 @@ from __future__ import annotations
14
14
 
15
15
  import json
16
16
  import logging
17
- import math
18
17
  import threading
19
18
  import time
20
19
  import uuid
@@ -30,8 +29,8 @@ import lancedb.index
30
29
  import numpy as np
31
30
  import pyarrow as pa
32
31
  import pyarrow.parquet as pq
33
-
34
- from filelock import FileLock, Timeout as FileLockTimeout
32
+ from filelock import FileLock
33
+ from filelock import Timeout as FileLockTimeout
35
34
 
36
35
  from spatial_memory.core.connection_pool import ConnectionPool
37
36
  from spatial_memory.core.db_idempotency import IdempotencyManager, IdempotencyRecord
@@ -47,8 +46,12 @@ from spatial_memory.core.errors import (
47
46
  StorageError,
48
47
  ValidationError,
49
48
  )
50
- from spatial_memory.core.filesystem import detect_filesystem_type, get_filesystem_warning_message, is_network_filesystem
51
- from spatial_memory.core.utils import to_aware_utc, utc_now
49
+ from spatial_memory.core.filesystem import (
50
+ detect_filesystem_type,
51
+ get_filesystem_warning_message,
52
+ is_network_filesystem,
53
+ )
54
+ from spatial_memory.core.utils import utc_now
52
55
 
53
56
  # Import centralized validation functions
54
57
  from spatial_memory.core.validation import (
@@ -221,7 +224,7 @@ def with_write_lock(func: F) -> F:
221
224
  Uses RLock to allow nested calls (e.g., bulk_import -> insert_batch).
222
225
  """
223
226
  @wraps(func)
224
- def wrapper(self: "Database", *args: Any, **kwargs: Any) -> Any:
227
+ def wrapper(self: Database, *args: Any, **kwargs: Any) -> Any:
225
228
  with self._write_lock:
226
229
  return func(self, *args, **kwargs)
227
230
  return cast(F, wrapper)
@@ -235,7 +238,7 @@ def with_stale_connection_recovery(func: F) -> F:
235
238
  reconnects, and retries the operation once.
236
239
  """
237
240
  @wraps(func)
238
- def wrapper(self: "Database", *args: Any, **kwargs: Any) -> Any:
241
+ def wrapper(self: Database, *args: Any, **kwargs: Any) -> Any:
239
242
  try:
240
243
  return func(self, *args, **kwargs)
241
244
  except Exception as e:
@@ -372,7 +375,7 @@ class ProcessLockManager:
372
375
  self._set_depth(depth - 1)
373
376
  return False # Still holding
374
377
 
375
- def __enter__(self) -> "ProcessLockManager":
378
+ def __enter__(self) -> ProcessLockManager:
376
379
  """Enter context manager - acquire lock."""
377
380
  self.acquire()
378
381
  return self
@@ -397,7 +400,7 @@ def with_process_lock(func: F) -> F:
397
400
  ...
398
401
  """
399
402
  @wraps(func)
400
- def wrapper(self: "Database", *args: Any, **kwargs: Any) -> Any:
403
+ def wrapper(self: Database, *args: Any, **kwargs: Any) -> Any:
401
404
  if self._process_lock is None:
402
405
  return func(self, *args, **kwargs)
403
406
  with self._process_lock:
@@ -1705,7 +1708,7 @@ class Database:
1705
1708
  old_namespace = _validate_namespace(old_namespace)
1706
1709
  new_namespace = _validate_namespace(new_namespace)
1707
1710
  safe_old = _sanitize_string(old_namespace)
1708
- safe_new = _sanitize_string(new_namespace)
1711
+ _sanitize_string(new_namespace) # Validate but don't store unused result
1709
1712
 
1710
1713
  try:
1711
1714
  # Check if source namespace exists
@@ -1835,7 +1838,7 @@ class Database:
1835
1838
  if not memory_ids:
1836
1839
  return None
1837
1840
 
1838
- safe_namespace = _sanitize_string(target_namespace)
1841
+ _sanitize_string(target_namespace) # Validate namespace
1839
1842
  now = utc_now()
1840
1843
 
1841
1844
  # Process in batches for large rollbacks
@@ -380,7 +380,8 @@ class IndexManager:
380
380
  index_type = "IVF_FLAT"
381
381
  sample_rate = max(16, count // 4) # Lower sample rate for small data
382
382
  else:
383
- index_type = self._db.index_type if self._db.index_type in ("IVF_PQ", "IVF_FLAT") else "IVF_PQ"
383
+ valid_types = ("IVF_PQ", "IVF_FLAT")
384
+ index_type = self._db.index_type if self._db.index_type in valid_types else "IVF_PQ"
384
385
 
385
386
  # Ensure num_partitions < num_vectors for KMeans clustering
386
387
  if num_partitions >= count:
@@ -24,7 +24,6 @@ Usage:
24
24
 
25
25
  from __future__ import annotations
26
26
 
27
- import json
28
27
  import logging
29
28
  from abc import ABC, abstractmethod
30
29
  from dataclasses import dataclass, field
@@ -18,6 +18,8 @@ import numpy as np
18
18
  from spatial_memory.core.errors import StorageError, ValidationError
19
19
  from spatial_memory.core.validation import (
20
20
  sanitize_string as _sanitize_string,
21
+ )
22
+ from spatial_memory.core.validation import (
21
23
  validate_namespace as _validate_namespace,
22
24
  )
23
25
 
@@ -312,7 +314,8 @@ class SearchManager:
312
314
  ])
313
315
 
314
316
  # Execute search and get results
315
- # LanceDB returns results with _query_index to identify which query each result belongs to
317
+ # LanceDB returns results with _query_index to identify which query
318
+ # each result belongs to
316
319
  search = search.limit(limit_per_query)
317
320
  results_df = search.to_pandas()
318
321
 
@@ -265,13 +265,13 @@ class EmbeddingService:
265
265
  backend="onnx",
266
266
  )
267
267
  logger.info(
268
- f"Using ONNX Runtime backend (2-3x faster inference)"
268
+ "Using ONNX Runtime backend (2-3x faster inference)"
269
269
  )
270
270
  else:
271
271
  # Use default PyTorch backend
272
272
  self._model = SentenceTransformer(self.model_name)
273
273
  logger.info(
274
- f"Using PyTorch backend"
274
+ "Using PyTorch backend"
275
275
  )
276
276
 
277
277
  self._dimensions = self._model.get_sentence_embedding_dimension()
@@ -23,7 +23,6 @@ import re
23
23
  import stat
24
24
  import urllib.parse
25
25
  from collections.abc import Sequence
26
- from io import BufferedReader
27
26
  from pathlib import Path
28
27
  from typing import BinaryIO
29
28
 
@@ -13,7 +13,6 @@ from __future__ import annotations
13
13
 
14
14
  from typing import Any, TypedDict
15
15
 
16
-
17
16
  # =============================================================================
18
17
  # Nested TypedDicts (shared across multiple responses)
19
18
  # =============================================================================
@@ -12,7 +12,6 @@ from typing import Any, Protocol
12
12
 
13
13
  import numpy as np
14
14
 
15
- from spatial_memory.core.errors import NamespaceNotFoundError
16
15
  from spatial_memory.core.models import Memory, MemoryResult
17
16
 
18
17
 
spatial_memory/server.py CHANGED
@@ -25,7 +25,6 @@ from mcp.types import TextContent, Tool
25
25
 
26
26
  from spatial_memory import __version__
27
27
  from spatial_memory.config import ConfigurationError, get_settings, validate_startup
28
- from spatial_memory.factory import ServiceFactory
29
28
  from spatial_memory.core.database import (
30
29
  clear_connection_cache,
31
30
  set_connection_pool_max_size,
@@ -46,6 +45,10 @@ from spatial_memory.core.errors import (
46
45
  SpatialMemoryError,
47
46
  ValidationError,
48
47
  )
48
+ from spatial_memory.core.health import HealthChecker
49
+ from spatial_memory.core.logging import configure_logging
50
+ from spatial_memory.core.metrics import is_available as metrics_available
51
+ from spatial_memory.core.metrics import record_request
49
52
  from spatial_memory.core.response_types import (
50
53
  ConsolidateResponse,
51
54
  DecayResponse,
@@ -71,15 +74,12 @@ from spatial_memory.core.response_types import (
71
74
  VisualizeResponse,
72
75
  WanderResponse,
73
76
  )
74
- from spatial_memory.core.health import HealthChecker
75
- from spatial_memory.core.logging import configure_logging
76
- from spatial_memory.core.metrics import is_available as metrics_available
77
- from spatial_memory.core.metrics import record_request
78
77
  from spatial_memory.core.tracing import (
79
78
  RequestContext,
80
79
  TimingContext,
81
80
  request_context,
82
81
  )
82
+ from spatial_memory.factory import ServiceFactory
83
83
  from spatial_memory.tools import TOOLS
84
84
 
85
85
  if TYPE_CHECKING:
@@ -999,10 +999,12 @@ class SpatialMemoryServer:
999
999
  """
1000
1000
  return '''## Spatial Memory System
1001
1001
 
1002
- You have access to a persistent semantic memory system. Use it proactively to build cumulative knowledge across sessions.
1002
+ You have access to a persistent semantic memory system. Use it proactively to
1003
+ build cumulative knowledge across sessions.
1003
1004
 
1004
1005
  ### Session Start
1005
- At conversation start, call `recall` with the user's apparent task/context to load relevant memories. Present insights naturally:
1006
+ At conversation start, call `recall` with the user's apparent task/context to
1007
+ load relevant memories. Present insights naturally:
1006
1008
  - Good: "Based on previous work, you decided to use PostgreSQL because..."
1007
1009
  - Bad: "The database returned: [{id: '...', content: '...'}]"
1008
1010
 
@@ -1013,11 +1015,13 @@ After these events, ask briefly "Save this? y/n" (minimal friction):
1013
1015
  - **Patterns**: "This pattern works...", "The trick is...", "Always do X when..."
1014
1016
  - **Discoveries**: "I found that...", "Important:...", "TIL..."
1015
1017
 
1016
- Do NOT ask for trivial information. Only prompt for insights that would help future sessions.
1018
+ Do NOT ask for trivial information. Only prompt for insights that would help
1019
+ future sessions.
1017
1020
 
1018
1021
  ### Saving Memories
1019
1022
  When user confirms, save with:
1020
- - **Detailed content**: Include full context, reasoning, and specifics. Future agents need complete information.
1023
+ - **Detailed content**: Include full context, reasoning, and specifics. Future
1024
+ agents need complete information.
1021
1025
  - **Contextual namespace**: Use project name, or categories like "decisions", "errors", "patterns"
1022
1026
  - **Descriptive tags**: Technologies, concepts, error types involved
1023
1027
  - **High importance (0.8-1.0)**: For decisions and critical fixes
@@ -7,6 +7,9 @@ from spatial_memory.core.errors import (
7
7
  NamespaceOperationError,
8
8
  ReinforcementError,
9
9
  )
10
+ from spatial_memory.services.export_import import (
11
+ ExportImportService,
12
+ )
10
13
  from spatial_memory.services.lifecycle import (
11
14
  ConsolidateResult,
12
15
  ConsolidationGroupResult,
@@ -33,9 +36,6 @@ from spatial_memory.services.spatial import (
33
36
  from spatial_memory.services.utility import (
34
37
  UtilityService,
35
38
  )
36
- from spatial_memory.services.export_import import (
37
- ExportImportService,
38
- )
39
39
 
40
40
  __all__ = [
41
41
  # Lifecycle
@@ -17,11 +17,11 @@ import csv
17
17
  import json
18
18
  import logging
19
19
  import time
20
- from collections.abc import Sequence
21
- from datetime import datetime, timezone
22
- from pathlib import Path
20
+ from collections.abc import Iterator, Sequence
21
+ from datetime import datetime
23
22
  from io import TextIOWrapper
24
- from typing import TYPE_CHECKING, Any, BinaryIO, Iterator
23
+ from pathlib import Path
24
+ from typing import TYPE_CHECKING, Any, BinaryIO
25
25
 
26
26
  import numpy as np
27
27
 
@@ -45,6 +45,8 @@ from spatial_memory.core.models import (
45
45
  logger = logging.getLogger(__name__)
46
46
 
47
47
  if TYPE_CHECKING:
48
+ import pyarrow as pa
49
+
48
50
  from spatial_memory.ports.repositories import (
49
51
  EmbeddingServiceProtocol,
50
52
  MemoryRepositoryProtocol,
@@ -504,7 +506,7 @@ class ExportImportService:
504
506
  # Export Format Handlers
505
507
  # =========================================================================
506
508
 
507
- def _create_parquet_schema(self, include_vectors: bool) -> "pa.Schema":
509
+ def _create_parquet_schema(self, include_vectors: bool) -> pa.Schema:
508
510
  """Create PyArrow schema for Parquet export.
509
511
 
510
512
  Args:
@@ -816,8 +818,7 @@ class ExportImportService:
816
818
  if content.startswith("["):
817
819
  # JSON array
818
820
  records = json.loads(content)
819
- for record in records:
820
- yield record
821
+ yield from records
821
822
  else:
822
823
  # JSON Lines (one object per line)
823
824
  for line in content.split("\n"):
@@ -959,7 +960,8 @@ class ExportImportService:
959
960
  ImportValidationError(
960
961
  row_number=row_number,
961
962
  field="vector",
962
- error=f"Vector dimension mismatch: expected {expected_dims}, got {actual_dims}",
963
+ error=f"Vector dimension mismatch: expected "
964
+ f"{expected_dims}, got {actual_dims}",
963
965
  value=f"[{actual_dims} dimensions]",
964
966
  )
965
967
  )
@@ -20,6 +20,10 @@ from typing import TYPE_CHECKING, Any, Literal
20
20
 
21
21
  import numpy as np
22
22
 
23
+ from spatial_memory.core.consolidation_strategies import (
24
+ ConsolidationAction,
25
+ get_strategy,
26
+ )
23
27
  from spatial_memory.core.errors import (
24
28
  ConsolidationError,
25
29
  DecayError,
@@ -27,10 +31,6 @@ from spatial_memory.core.errors import (
27
31
  ReinforcementError,
28
32
  ValidationError,
29
33
  )
30
- from spatial_memory.core.consolidation_strategies import (
31
- ConsolidationAction,
32
- get_strategy,
33
- )
34
34
  from spatial_memory.core.lifecycle_ops import (
35
35
  apply_decay,
36
36
  calculate_decay_factor,
@@ -52,11 +52,11 @@ from spatial_memory.core.models import (
52
52
  ReinforcedMemory,
53
53
  ReinforceResult,
54
54
  )
55
+ from spatial_memory.core.utils import to_naive_utc, utc_now, utc_now_naive
56
+ from spatial_memory.core.validation import validate_namespace
55
57
 
56
58
  # Alias for backward compatibility
57
59
  ConsolidationGroupResult = ConsolidationGroup
58
- from spatial_memory.core.utils import to_naive_utc, utc_now, utc_now_naive
59
- from spatial_memory.core.validation import validate_namespace
60
60
 
61
61
  logger = logging.getLogger(__name__)
62
62
 
@@ -384,7 +384,8 @@ class LifecycleService:
384
384
  # Calculate reinforcement for all found memories
385
385
  now = utc_now()
386
386
  batch_updates: list[tuple[str, dict[str, Any]]] = []
387
- reinforcement_info: list[tuple[str, Memory, float, float]] = [] # id, memory, new_imp, boost
387
+ # Tuple: (id, memory, new_importance, boost_applied)
388
+ reinforcement_info: list[tuple[str, Memory, float, float]] = []
388
389
 
389
390
  for memory_id, memory in memory_map.items():
390
391
  # Calculate new importance
@@ -413,7 +414,9 @@ class LifecycleService:
413
414
  f"{len(batch_failed_ids)} failed"
414
415
  )
415
416
  except Exception as e:
416
- logger.warning(f"Batch reinforce update failed: {e}, falling back to individual updates")
417
+ logger.warning(
418
+ f"Batch reinforce update failed: {e}, falling back to individual updates"
419
+ )
417
420
  # Fall back to individual updates on batch failure
418
421
  batch_failed_ids = []
419
422
  for memory_id, updates in batch_updates:
@@ -267,8 +267,11 @@ class SpatialService:
267
267
  steps_with_memories += 1
268
268
 
269
269
  # Use 0.0 if no memories found (inf means no distance calculated)
270
- # Clamp to 0.0 to handle floating point precision errors (e.g., -4.89e-08)
271
- final_distance = 0.0 if distance_to_path == float("inf") else max(0.0, distance_to_path)
270
+ # Clamp to 0.0 to handle floating point precision errors
271
+ if distance_to_path == float("inf"):
272
+ final_distance = 0.0
273
+ else:
274
+ final_distance = max(0.0, distance_to_path)
272
275
  journey_steps.append(
273
276
  JourneyStep(
274
277
  step=step_num,
@@ -243,7 +243,8 @@ class UtilityService:
243
243
  namespace=namespace,
244
244
  memories_deleted=memory_count,
245
245
  success=True,
246
- message=f"DRY RUN: Would delete {memory_count} memories from namespace '{namespace}'",
246
+ message=f"DRY RUN: Would delete {memory_count} memories "
247
+ f"from namespace '{namespace}'",
247
248
  dry_run=True,
248
249
  )
249
250
 
@@ -261,7 +262,7 @@ class UtilityService:
261
262
  namespace=namespace,
262
263
  memories_deleted=deleted_count,
263
264
  success=True,
264
- message=f"Successfully deleted {deleted_count} memories from namespace '{namespace}'",
265
+ message=f"Deleted {deleted_count} memories from namespace '{namespace}'",
265
266
  dry_run=False,
266
267
  )
267
268
 
@@ -313,7 +314,8 @@ class UtilityService:
313
314
  new_namespace=new_namespace,
314
315
  memories_renamed=renamed_count,
315
316
  success=True,
316
- message=f"Successfully renamed {renamed_count} memories from '{old_namespace}' to '{new_namespace}'",
317
+ message=f"Renamed {renamed_count} memories "
318
+ f"from '{old_namespace}' to '{new_namespace}'",
317
319
  )
318
320
 
319
321
  except NamespaceNotFoundError:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: spatial-memory-mcp
3
- Version: 1.6.0
3
+ Version: 1.6.2
4
4
  Summary: Spatial bidirectional persistent memory MCP server for LLMs - vector-based semantic memory as a navigable landscape
5
5
  Project-URL: Homepage, https://github.com/arman-tech/spatial-memory-mcp
6
6
  Project-URL: Repository, https://github.com/arman-tech/spatial-memory-mcp
@@ -42,9 +42,13 @@ Description-Content-Type: text/markdown
42
42
 
43
43
  # Spatial Memory MCP Server
44
44
 
45
+ [![PyPI version](https://badge.fury.io/py/spatial-memory-mcp.svg)](https://pypi.org/project/spatial-memory-mcp/)
46
+ [![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
47
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
48
+
45
49
  A vector-based spatial memory system that treats knowledge as a navigable landscape, not a filing cabinet.
46
50
 
47
- > **Project Status**: All phases complete. Production-ready with 1360 tests passing.
51
+ > **Version 1.6.2** Production-ready with 1,360 tests passing.
48
52
 
49
53
  ## Supported Platforms
50
54
 
@@ -91,7 +95,7 @@ Navigate knowledge like a landscape, not a filing cabinet:
91
95
  | **Regions** | HDBSCAN clustering—see how your knowledge self-organizes |
92
96
  | **Visualize** | UMAP projection—view your memory space in 2D/3D |
93
97
 
94
- ### 21 Tools vs. 3-6 in Competitors
98
+ ### 22 Tools vs. 3-6 in Competitors
95
99
  Full lifecycle management: core operations, spatial navigation, memory lifecycle, hybrid search, namespace management, data import/export, and health/stats monitoring.
96
100
 
97
101
  ### Enterprise-Ready
@@ -101,7 +105,7 @@ Connection pooling, circuit breakers, per-agent rate limiting, request tracing,
101
105
 
102
106
  ## Features
103
107
 
104
- - **21 MCP tools** across 4 categories (core, spatial, lifecycle, utility)
108
+ - **22 MCP tools** across 4 categories (core, spatial, lifecycle, utility)
105
109
  - **Clean Architecture** with ports/adapters pattern for testability
106
110
  - **LanceDB** vector storage with automatic indexing
107
111
  - **Dual embedding support**: Local (sentence-transformers) or OpenAI API
@@ -119,10 +123,19 @@ Connection pooling, circuit breakers, per-agent rate limiting, request tracing,
119
123
  | Phase 3: Spatial Operations | Complete | `journey`, `wander`, `regions`, `visualize` |
120
124
  | Phase 4: Lifecycle Operations | Complete | `consolidate`, `extract`, `decay`, `reinforce` |
121
125
  | Phase 5: Utilities | Complete | `stats`, `namespaces`, `export`, `import`, `hybrid_recall` |
122
- | Phase 6: Polish & Release | In Progress | PyPI release pending |
126
+ | Phase 6: Polish & Release | Complete | v1.6.0 on PyPI |
123
127
 
124
128
  ## Installation
125
129
 
130
+ ### From PyPI (Recommended)
131
+
132
+ ```bash
133
+ pip install spatial-memory-mcp
134
+
135
+ # Or with uv
136
+ uv pip install spatial-memory-mcp
137
+ ```
138
+
126
139
  ### Development Setup
127
140
 
128
141
  ```bash
@@ -134,6 +147,10 @@ pip install -e ".[dev]"
134
147
  ### With OpenAI Support
135
148
 
136
149
  ```bash
150
+ # From PyPI
151
+ pip install spatial-memory-mcp[openai]
152
+
153
+ # From source
137
154
  pip install -e ".[dev,openai]"
138
155
  ```
139
156
 
@@ -166,6 +183,28 @@ If ONNX shows as unavailable, reinstall with:
166
183
  pip install --force-reinstall "sentence-transformers[onnx]"
167
184
  ```
168
185
 
186
+ ### CLI Commands
187
+
188
+ The `spatial-memory` CLI provides several commands:
189
+
190
+ ```bash
191
+ # Start the MCP server (default)
192
+ spatial-memory serve
193
+
194
+ # View the MCP instructions injected into Claude's context
195
+ spatial-memory instructions
196
+
197
+ # Run database migrations
198
+ spatial-memory migrate --status # Check migration status
199
+ spatial-memory migrate --dry-run # Preview migrations
200
+ spatial-memory migrate # Apply pending migrations
201
+
202
+ # Show version
203
+ spatial-memory --version
204
+ ```
205
+
206
+ The `instructions` command is useful for understanding what behavioral guidelines are automatically injected when the MCP server connects to Claude.
207
+
169
208
  ### Optional Performance Dependencies
170
209
 
171
210
  For best performance, install these optional dependencies:
@@ -257,7 +296,7 @@ Add to your Claude Desktop config (`claude_desktop_config.json`):
257
296
  }
258
297
  ```
259
298
 
260
- ## Available Tools (21 Total)
299
+ ## Available Tools (22 Total)
261
300
 
262
301
  For complete API documentation including parameters, return types, and examples, see [docs/API.md](docs/API.md).
263
302
 
@@ -301,6 +340,7 @@ For complete API documentation including parameters, return types, and examples,
301
340
  | `export_memories` | Export memories to Parquet, JSON, or CSV format |
302
341
  | `import_memories` | Import memories from exported files with validation |
303
342
  | `hybrid_recall` | Combined vector + full-text search with configurable weighting |
343
+ | `health` | Check system health status |
304
344
 
305
345
  ## Tool Examples
306
346
 
@@ -348,7 +388,7 @@ Export all memories to parquet format
348
388
 
349
389
  - **Path Traversal Prevention**: All file operations validate paths against allowed directories
350
390
  - **Symlink Attack Protection**: Optional symlink blocking for sensitive environments
351
- - **SQL Injection Prevention**: 15+ dangerous patterns detected and blocked
391
+ - **SQL Injection Prevention**: 13 patterns covering major attack vectors
352
392
  - **Input Validation**: Pydantic models validate all inputs
353
393
  - **Error Sanitization**: Internal errors return reference IDs, not stack traces
354
394
  - **Secure Credential Handling**: API keys stored as SecretStr
@@ -418,7 +458,7 @@ See [SPATIAL-MEMORY-ARCHITECTURE-DIAGRAMS.md](SPATIAL-MEMORY-ARCHITECTURE-DIAGRA
418
458
 
419
459
  | Document | Description |
420
460
  |----------|-------------|
421
- | [docs/API.md](docs/API.md) | Complete API reference for all 21 tools |
461
+ | [docs/API.md](docs/API.md) | Complete API reference for all 22 tools |
422
462
  | [docs/BENCHMARKS.md](docs/BENCHMARKS.md) | Performance benchmarks and test results |
423
463
  | [docs/METRICS.md](docs/METRICS.md) | Prometheus metrics documentation |
424
464
  | [docs/troubleshooting.md](docs/troubleshooting.md) | Troubleshooting guide |
@@ -450,7 +490,9 @@ For security vulnerabilities, please email directly rather than opening a public
450
490
 
451
491
  ## For Claude Code Users
452
492
 
453
- This project includes [CLAUDE.md](CLAUDE.md) with instructions for the Claude Code AI assistant to interact with the memory system.
493
+ When the MCP server connects, behavioral instructions are **automatically injected** into Claude's context—no configuration needed. Run `spatial-memory instructions` to view what gets injected.
494
+
495
+ For contributors working on this codebase, [CLAUDE.md](CLAUDE.md) provides project-specific guidance for AI assistants.
454
496
 
455
497
  ## License
456
498
 
@@ -1,26 +1,26 @@
1
- spatial_memory/__init__.py,sha256=5llnvvlYGS28SmMQcE_DhSSTaFyvhh0BASb-ZHX4Z1o,2154
2
- spatial_memory/__main__.py,sha256=PaB4lkEBePNFCFDwjZo2mtQiWCNbK6U0fZ8jsQ9luNE,7761
3
- spatial_memory/config.py,sha256=SvG67Z8Hjw0XAFzVn59lLm-_Pz5dzL-c4Dli3_mtG0M,22537
1
+ spatial_memory/__init__.py,sha256=TjqwnyL1ZN23Q483OYIlPWXq-FcPmShuLQ9J4xPIyJs,2154
2
+ spatial_memory/__main__.py,sha256=1WK2evonr4Sv1wZNbBuQHQ_z14Aa9kJr2w3GwDlz04I,8279
3
+ spatial_memory/config.py,sha256=2vUUi39QnLSglEnkOVp748OIwTltTXa0C6HGf55_LNQ,22503
4
4
  spatial_memory/factory.py,sha256=iuVKeE0q9SrDo816k2H744nELFeq7vVOdg4puHxCFOM,15806
5
5
  spatial_memory/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
- spatial_memory/server.py,sha256=4a4WbS_Us0OiLfRyt5Mj3WU9rMCdMRbU6ziWajG-72I,45779
6
+ spatial_memory/server.py,sha256=PduECYXoMRpXLHATPyT_uJxpq5LszI6g-GBLYBC1hC8,45785
7
7
  spatial_memory/verify.py,sha256=4p4KQYRUBrKGax66n629hvb9Ul8sR2yXXnfyZLpNk-o,3939
8
8
  spatial_memory/adapters/__init__.py,sha256=xNPQCOYVsTP2ogMEcYGbxGJYH9pdksB66MZ7ctK6KbM,187
9
9
  spatial_memory/adapters/lancedb_repository.py,sha256=NwZQ-SGPTe82cFbOYtYERPRvY3eujz5iCd7EOaLiDfE,31247
10
- spatial_memory/core/__init__.py,sha256=wG6fws4AIF3X1vJdWA2_w2bMQo4ZXez_BYtcYvFGQvY,3033
10
+ spatial_memory/core/__init__.py,sha256=MWU1dWaE-8opHiNgTgn8Jd1MhCWfRTSbrHwlzR6lgkk,3033
11
11
  spatial_memory/core/cache.py,sha256=QqG0hhpaDH0mzBLIEinGP3WkKsb70QfCLMGpptguWIM,10038
12
12
  spatial_memory/core/circuit_breaker.py,sha256=zxqnOWiAnx_S7oX44UY57ihpk7V27fzW6rYgBn1BWp8,10734
13
13
  spatial_memory/core/connection_pool.py,sha256=ienTFQ-tFYwkaWD2_lcs9T8uYXL45OMpzCX5V-l_MMk,7617
14
- spatial_memory/core/consolidation_strategies.py,sha256=_PGdVuz4Kkf96cdIEPieGTOfubgOc6PoUYuXfJRwBd8,12805
15
- spatial_memory/core/database.py,sha256=3Llo2FLznQA2zUYf5r1JFnht61bPZQGTGeZ2IVhxDMI,118227
14
+ spatial_memory/core/consolidation_strategies.py,sha256=u-s5uGrx9RpwJkkoU6gWFASCWrhWneAh9UVXXPMZHjw,12782
15
+ spatial_memory/core/database.py,sha256=5Sn0xJ0PZD-aOBlV1n9IUBJK6DzxvmUTT4iOzTyiqz8,118268
16
16
  spatial_memory/core/db_idempotency.py,sha256=B0EYdZFZYmQ7s101RviswySta7Qp7TZ2fiqWES_djyw,7978
17
- spatial_memory/core/db_indexes.py,sha256=p1glBuna81yY8bu8hhJkR6AhuzeZgaAaeKnsd3Oe4No,20115
18
- spatial_memory/core/db_migrations.py,sha256=x-_dXZrtfZZQwb4d3ZW32zw1-CzbDLC7Y33fdsvQM5Y,19138
19
- spatial_memory/core/db_search.py,sha256=XnNpqI2oto9EKbmp7bYBxeaxGfblJicR9KazvZKfhbg,19866
17
+ spatial_memory/core/db_indexes.py,sha256=dqM-HLy4hfL9pxgr11z0mUPGlHFIC1DJh09eHjiVNwU,20153
18
+ spatial_memory/core/db_migrations.py,sha256=1lv6YvLMon_cJprsHVHu4uDLy8JeptaOWE_Ig0mJ-3Q,19126
19
+ spatial_memory/core/db_search.py,sha256=mQE-fU6JUxThlBm2HOB3T6Bn_IxPJ18X7AvruR98Htc,19927
20
20
  spatial_memory/core/db_versioning.py,sha256=7LGWQO6EiwIgw-C5e81xG4jEO34b5y95Ag6uoVrU7Xw,5984
21
- spatial_memory/core/embeddings.py,sha256=g_C8rmrNH8qTroPcg-aYJo5Z6NR_YqGN050Iryytx5c,20892
21
+ spatial_memory/core/embeddings.py,sha256=hixE3FakjUnjsL8nkqZ4EE8iP3XKApCniSuedp3Gt8A,20890
22
22
  spatial_memory/core/errors.py,sha256=mGQlPNNiNOdErYPXdEQXM1_-IeueUB_jtgdt8P8lzUQ,8799
23
- spatial_memory/core/file_security.py,sha256=kHIYEnZIRFz94FxCJ7oOHiaihgQRB1rsOHHmJprHNhU,25766
23
+ spatial_memory/core/file_security.py,sha256=uBJDGhJNZutUCI2re2Gh0gnpY2R5V5lyTxGDZIWrhsw,25736
24
24
  spatial_memory/core/filesystem.py,sha256=aE8BvM8tyIMbjtaiyG0Si0F1c85jxAwa3IM5I_kvkME,5602
25
25
  spatial_memory/core/health.py,sha256=Xq9TYfmBN3YLjYOrpFWtvbR1-fQbSrP1oorSVjRHOSg,9145
26
26
  spatial_memory/core/helpers.py,sha256=nxLXGfkpydWzEgMj8PkdX9gVvybN2aCH-CfbEkq6U_w,1931
@@ -30,7 +30,7 @@ spatial_memory/core/logging.py,sha256=JfFRzHmhZ2BPNSJiKIHGjfUeskFVo8Bj7nOKznvv0k
30
30
  spatial_memory/core/metrics.py,sha256=8B26sAd2y6xrpaJr8mNgOAMzAZDd1uXOvAGxz_1nhfY,5383
31
31
  spatial_memory/core/models.py,sha256=VX61h5_pnsIQ5w5LjpElhVTW4UAa0RKadnrtLLOQb94,17353
32
32
  spatial_memory/core/rate_limiter.py,sha256=5A3YI6C0_YrWZeSBBxF7Eu5HUD8rodS45301730doF0,10582
33
- spatial_memory/core/response_types.py,sha256=VhfQLpTxgdJf3CYPtQALvh4KmaUbHzVAT_qtRVtoQgs,10603
33
+ spatial_memory/core/response_types.py,sha256=X4wxPQq-BkochwqSjTkMQZ-J6BhupeI1wvV5V1q7s2c,10602
34
34
  spatial_memory/core/security.py,sha256=fjIYqsyzK4qqm7sI8FNEE2xx9WjNJnrAslOBLVRVwgs,19759
35
35
  spatial_memory/core/spatial_ops.py,sha256=_xNrZzrbL7w2uAMJkQZEtTMjERQpo04cuSUoTNebiew,13360
36
36
  spatial_memory/core/tracing.py,sha256=9O3WdUJfCl2sohYWlaQETrCO7_P_N3qY_MqSAnpQPl0,8438
@@ -38,17 +38,17 @@ spatial_memory/core/utils.py,sha256=YvvU3EbbAicR732LkHMM5-u4wvBaJ4G9DigBaB2CoI4,
38
38
  spatial_memory/core/validation.py,sha256=A8a5PF7X8Veg8S176UFEqkZDBlWILbQM-5wtAMOgG3U,13476
39
39
  spatial_memory/migrations/__init__.py,sha256=wljoV_u2PPx-dH6JOPmjEP5xEbwoM9HQ1WYDZr7PW58,1072
40
40
  spatial_memory/ports/__init__.py,sha256=Lq9ht9AS4VwPbMojtd_FYkA7lUuCXmYHwv6sweJi9AQ,243
41
- spatial_memory/ports/repositories.py,sha256=oJMU7UHoj4YudyeOQaSkI9A2z81L3Vn2q7hm3RILfXI,19920
42
- spatial_memory/services/__init__.py,sha256=epaF3aHxK2sgGVMp6rS_fxMMAvDVPxjaWm1n4hKOMWU,1564
43
- spatial_memory/services/export_import.py,sha256=2vZnFvX1deV-Zdj0HGkc2My8Oy1BrFJL8Peep25iUKI,38190
44
- spatial_memory/services/lifecycle.py,sha256=asxFBp06qfnaZJpAph6Dm6i7kN1cREXuoopkjuOMvwc,42937
41
+ spatial_memory/ports/repositories.py,sha256=6rUxGUfeAVudNU9ugaVTKedPGQONaIL0TrSQt7XR5HU,19857
42
+ spatial_memory/services/__init__.py,sha256=9sYpYgQRTAq800I5ZS_GFcg5F_p3dUySe5fKN3S4vg4,1564
43
+ spatial_memory/services/export_import.py,sha256=Ui1RFujtEhrDYKGXsQragUtpVfxq0eLwjnabB1h-F7c,38211
44
+ spatial_memory/services/lifecycle.py,sha256=y1XSjJuCBou7wPdbRGyZsP30URw6iNqxjhlwYMLv79o,43010
45
45
  spatial_memory/services/memory.py,sha256=MZ9NMNXBRYEA39vzT5gAB7PXJrGFwC-D98SLZe7Z50Q,12944
46
- spatial_memory/services/spatial.py,sha256=3UMPm4mRQ42oXNwLUEYp4SAinnGX4dwOnWaK9CkVViA,42552
47
- spatial_memory/services/utility.py,sha256=89rn1gNJwNQIhrWjmVS3RKP5AQuCvjswFeefMp7yK-4,14950
46
+ spatial_memory/services/spatial.py,sha256=x-d8ucSpP1sNQR9ywylMwF884hYPkRDfNDhDGfUodwI,42609
47
+ spatial_memory/services/utility.py,sha256=63i33hCnC9C2tLpTtGhuQ87_K4yU-sZMU2c7ldT24wM,14968
48
48
  spatial_memory/tools/__init__.py,sha256=ZhFZp5j8HA4Qx5pVcRmgTcBbqY3X5TmgMNpSkyAMqJA,127
49
49
  spatial_memory/tools/definitions.py,sha256=Ueg_BrRGJcp_jnQD95DiYFPkxU419XPkbjzQFDG3jtY,25397
50
- spatial_memory_mcp-1.6.0.dist-info/METADATA,sha256=SKMn9h_8wYhMK45Vh5iqkH8-HSyjaf5r96Fkyv0tBek,15438
51
- spatial_memory_mcp-1.6.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
52
- spatial_memory_mcp-1.6.0.dist-info/entry_points.txt,sha256=nJ4RJBB9SvhNktJdikcAS27fSwtKekpgPR4GTy2r1cE,64
53
- spatial_memory_mcp-1.6.0.dist-info/licenses/LICENSE,sha256=g65vrroU3yJxekbYV8xmDj7KFrXAg89eCM8vcWrpKmU,1095
54
- spatial_memory_mcp-1.6.0.dist-info/RECORD,,
50
+ spatial_memory_mcp-1.6.2.dist-info/METADATA,sha256=CpNnbu3XX3URUhRgGkQuTJdeLr9PQE9TLQri34GVBk8,16772
51
+ spatial_memory_mcp-1.6.2.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
52
+ spatial_memory_mcp-1.6.2.dist-info/entry_points.txt,sha256=nJ4RJBB9SvhNktJdikcAS27fSwtKekpgPR4GTy2r1cE,64
53
+ spatial_memory_mcp-1.6.2.dist-info/licenses/LICENSE,sha256=g65vrroU3yJxekbYV8xmDj7KFrXAg89eCM8vcWrpKmU,1095
54
+ spatial_memory_mcp-1.6.2.dist-info/RECORD,,