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.
- spatial_memory/__init__.py +1 -1
- spatial_memory/__main__.py +21 -4
- spatial_memory/config.py +1 -1
- spatial_memory/core/__init__.py +2 -2
- spatial_memory/core/consolidation_strategies.py +0 -1
- spatial_memory/core/database.py +14 -11
- spatial_memory/core/db_indexes.py +2 -1
- spatial_memory/core/db_migrations.py +0 -1
- spatial_memory/core/db_search.py +4 -1
- spatial_memory/core/embeddings.py +2 -2
- spatial_memory/core/file_security.py +0 -1
- spatial_memory/core/response_types.py +0 -1
- spatial_memory/ports/repositories.py +0 -1
- spatial_memory/server.py +13 -9
- spatial_memory/services/__init__.py +3 -3
- spatial_memory/services/export_import.py +10 -8
- spatial_memory/services/lifecycle.py +11 -8
- spatial_memory/services/spatial.py +5 -2
- spatial_memory/services/utility.py +5 -3
- {spatial_memory_mcp-1.6.0.dist-info → spatial_memory_mcp-1.6.2.dist-info}/METADATA +51 -9
- {spatial_memory_mcp-1.6.0.dist-info → spatial_memory_mcp-1.6.2.dist-info}/RECORD +24 -24
- {spatial_memory_mcp-1.6.0.dist-info → spatial_memory_mcp-1.6.2.dist-info}/WHEEL +0 -0
- {spatial_memory_mcp-1.6.0.dist-info → spatial_memory_mcp-1.6.2.dist-info}/entry_points.txt +0 -0
- {spatial_memory_mcp-1.6.0.dist-info → spatial_memory_mcp-1.6.2.dist-info}/licenses/LICENSE +0 -0
spatial_memory/__init__.py
CHANGED
spatial_memory/__main__.py
CHANGED
|
@@ -44,7 +44,7 @@ def run_migrate(args: argparse.Namespace) -> int:
|
|
|
44
44
|
format="%(levelname)s: %(message)s",
|
|
45
45
|
)
|
|
46
46
|
|
|
47
|
-
print(
|
|
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(
|
|
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
|
-
|
|
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 == "
|
|
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'
|
|
50
|
+
description="Embedding backend: 'auto', 'onnx', or 'pytorch'",
|
|
51
51
|
)
|
|
52
52
|
|
|
53
53
|
# OpenAI (optional)
|
spatial_memory/core/__init__.py
CHANGED
|
@@ -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.
|
|
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
|
spatial_memory/core/database.py
CHANGED
|
@@ -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
|
|
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
|
|
51
|
-
|
|
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:
|
|
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:
|
|
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) ->
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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:
|
spatial_memory/core/db_search.py
CHANGED
|
@@ -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
|
|
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
|
-
|
|
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
|
-
|
|
274
|
+
"Using PyTorch backend"
|
|
275
275
|
)
|
|
276
276
|
|
|
277
277
|
self._dimensions = self._model.get_sentence_embedding_dimension()
|
|
@@ -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
|
# =============================================================================
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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) ->
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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(
|
|
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
|
|
271
|
-
|
|
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
|
|
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"
|
|
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"
|
|
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.
|
|
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
|
+
[](https://pypi.org/project/spatial-memory-mcp/)
|
|
46
|
+
[](https://www.python.org/downloads/)
|
|
47
|
+
[](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
|
-
> **
|
|
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
|
-
###
|
|
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
|
-
- **
|
|
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 |
|
|
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 (
|
|
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**:
|
|
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
|
|
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
|
-
|
|
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=
|
|
2
|
-
spatial_memory/__main__.py,sha256=
|
|
3
|
-
spatial_memory/config.py,sha256=
|
|
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=
|
|
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=
|
|
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=
|
|
15
|
-
spatial_memory/core/database.py,sha256=
|
|
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=
|
|
18
|
-
spatial_memory/core/db_migrations.py,sha256=
|
|
19
|
-
spatial_memory/core/db_search.py,sha256=
|
|
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=
|
|
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=
|
|
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=
|
|
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=
|
|
42
|
-
spatial_memory/services/__init__.py,sha256=
|
|
43
|
-
spatial_memory/services/export_import.py,sha256=
|
|
44
|
-
spatial_memory/services/lifecycle.py,sha256=
|
|
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=
|
|
47
|
-
spatial_memory/services/utility.py,sha256=
|
|
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.
|
|
51
|
-
spatial_memory_mcp-1.6.
|
|
52
|
-
spatial_memory_mcp-1.6.
|
|
53
|
-
spatial_memory_mcp-1.6.
|
|
54
|
-
spatial_memory_mcp-1.6.
|
|
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,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|