This is page 4 of 46. Use http://codebase.md/doobidoo/mcp-memory-service?page={x} to view the full context.
# Directory Structure
```
├── .claude
│ ├── agents
│ │ ├── amp-bridge.md
│ │ ├── amp-pr-automator.md
│ │ ├── code-quality-guard.md
│ │ ├── gemini-pr-automator.md
│ │ └── github-release-manager.md
│ ├── commands
│ │ ├── README.md
│ │ ├── refactor-function
│ │ ├── refactor-function-prod
│ │ └── refactor-function.md
│ ├── consolidation-fix-handoff.md
│ ├── consolidation-hang-fix-summary.md
│ ├── directives
│ │ ├── agents.md
│ │ ├── code-quality-workflow.md
│ │ ├── consolidation-details.md
│ │ ├── development-setup.md
│ │ ├── hooks-configuration.md
│ │ ├── memory-first.md
│ │ ├── memory-tagging.md
│ │ ├── pr-workflow.md
│ │ ├── quality-system-details.md
│ │ ├── README.md
│ │ ├── refactoring-checklist.md
│ │ ├── storage-backends.md
│ │ └── version-management.md
│ ├── prompts
│ │ └── hybrid-cleanup-integration.md
│ ├── settings.local.json.backup
│ └── settings.local.json.local
├── .commit-message
├── .coveragerc
├── .dockerignore
├── .env.example
├── .env.sqlite.backup
├── .envnn#
├── .gitattributes
├── .github
│ ├── FUNDING.yml
│ ├── ISSUE_TEMPLATE
│ │ ├── bug_report.yml
│ │ ├── config.yml
│ │ ├── feature_request.yml
│ │ └── performance_issue.yml
│ ├── pull_request_template.md
│ └── workflows
│ ├── bridge-tests.yml
│ ├── CACHE_FIX.md
│ ├── claude-branch-automation.yml
│ ├── claude-code-review.yml
│ ├── claude.yml
│ ├── cleanup-images.yml.disabled
│ ├── dev-setup-validation.yml
│ ├── docker-publish.yml
│ ├── dockerfile-lint.yml
│ ├── LATEST_FIXES.md
│ ├── main-optimized.yml.disabled
│ ├── main.yml
│ ├── publish-and-test.yml
│ ├── publish-dual.yml
│ ├── README_OPTIMIZATION.md
│ ├── release-tag.yml.disabled
│ ├── release.yml
│ ├── roadmap-review-reminder.yml
│ ├── SECRET_CONDITIONAL_FIX.md
│ └── WORKFLOW_FIXES.md
├── .gitignore
├── .mcp.json.backup
├── .mcp.json.template
├── .metrics
│ ├── baseline_cc_install_hooks.txt
│ ├── baseline_mi_install_hooks.txt
│ ├── baseline_nesting_install_hooks.txt
│ ├── BASELINE_REPORT.md
│ ├── COMPLEXITY_COMPARISON.txt
│ ├── QUICK_REFERENCE.txt
│ ├── README.md
│ ├── REFACTORED_BASELINE.md
│ ├── REFACTORING_COMPLETION_REPORT.md
│ └── TRACKING_TABLE.md
├── .pyscn
│ ├── .gitignore
│ └── reports
│ └── analyze_20251123_214224.html
├── AGENTS.md
├── ai-optimized-tool-descriptions.py
├── archive
│ ├── deployment
│ │ ├── deploy_fastmcp_fixed.sh
│ │ ├── deploy_http_with_mcp.sh
│ │ └── deploy_mcp_v4.sh
│ ├── deployment-configs
│ │ ├── empty_config.yml
│ │ └── smithery.yaml
│ ├── development
│ │ └── test_fastmcp.py
│ ├── docs-removed-2025-08-23
│ │ ├── authentication.md
│ │ ├── claude_integration.md
│ │ ├── claude-code-compatibility.md
│ │ ├── claude-code-integration.md
│ │ ├── claude-code-quickstart.md
│ │ ├── claude-desktop-setup.md
│ │ ├── complete-setup-guide.md
│ │ ├── database-synchronization.md
│ │ ├── development
│ │ │ ├── autonomous-memory-consolidation.md
│ │ │ ├── CLEANUP_PLAN.md
│ │ │ ├── CLEANUP_README.md
│ │ │ ├── CLEANUP_SUMMARY.md
│ │ │ ├── dream-inspired-memory-consolidation.md
│ │ │ ├── hybrid-slm-memory-consolidation.md
│ │ │ ├── mcp-milestone.md
│ │ │ ├── multi-client-architecture.md
│ │ │ ├── test-results.md
│ │ │ └── TIMESTAMP_FIX_SUMMARY.md
│ │ ├── distributed-sync.md
│ │ ├── invocation_guide.md
│ │ ├── macos-intel.md
│ │ ├── master-guide.md
│ │ ├── mcp-client-configuration.md
│ │ ├── multi-client-server.md
│ │ ├── service-installation.md
│ │ ├── sessions
│ │ │ └── MCP_ENHANCEMENT_SESSION_MEMORY_v4.1.0.md
│ │ ├── UBUNTU_SETUP.md
│ │ ├── ubuntu.md
│ │ ├── windows-setup.md
│ │ └── windows.md
│ ├── docs-root-cleanup-2025-08-23
│ │ ├── AWESOME_LIST_SUBMISSION.md
│ │ ├── CLOUDFLARE_IMPLEMENTATION.md
│ │ ├── DOCUMENTATION_ANALYSIS.md
│ │ ├── DOCUMENTATION_CLEANUP_PLAN.md
│ │ ├── DOCUMENTATION_CONSOLIDATION_COMPLETE.md
│ │ ├── LITESTREAM_SETUP_GUIDE.md
│ │ ├── lm_studio_system_prompt.md
│ │ ├── PYTORCH_DOWNLOAD_FIX.md
│ │ └── README-ORIGINAL-BACKUP.md
│ ├── investigations
│ │ └── MACOS_HOOKS_INVESTIGATION.md
│ ├── litestream-configs-v6.3.0
│ │ ├── install_service.sh
│ │ ├── litestream_master_config_fixed.yml
│ │ ├── litestream_master_config.yml
│ │ ├── litestream_replica_config_fixed.yml
│ │ ├── litestream_replica_config.yml
│ │ ├── litestream_replica_simple.yml
│ │ ├── litestream-http.service
│ │ ├── litestream.service
│ │ └── requirements-cloudflare.txt
│ ├── release-notes
│ │ └── release-notes-v7.1.4.md
│ └── setup-development
│ ├── README.md
│ ├── setup_consolidation_mdns.sh
│ ├── STARTUP_SETUP_GUIDE.md
│ └── test_service.sh
├── CHANGELOG-HISTORIC.md
├── CHANGELOG.md
├── claude_commands
│ ├── memory-context.md
│ ├── memory-health.md
│ ├── memory-ingest-dir.md
│ ├── memory-ingest.md
│ ├── memory-recall.md
│ ├── memory-search.md
│ ├── memory-store.md
│ ├── README.md
│ └── session-start.md
├── claude-hooks
│ ├── config.json
│ ├── config.template.json
│ ├── CONFIGURATION.md
│ ├── core
│ │ ├── auto-capture-hook.js
│ │ ├── auto-capture-hook.ps1
│ │ ├── memory-retrieval.js
│ │ ├── mid-conversation.js
│ │ ├── permission-request.js
│ │ ├── session-end.js
│ │ ├── session-start.js
│ │ └── topic-change.js
│ ├── debug-pattern-test.js
│ ├── install_claude_hooks_windows.ps1
│ ├── install_hooks.py
│ ├── memory-mode-controller.js
│ ├── MIGRATION.md
│ ├── README-AUTO-CAPTURE.md
│ ├── README-NATURAL-TRIGGERS.md
│ ├── README-PERMISSION-REQUEST.md
│ ├── README-phase2.md
│ ├── README.md
│ ├── simple-test.js
│ ├── statusline.sh
│ ├── test-adaptive-weights.js
│ ├── test-dual-protocol-hook.js
│ ├── test-mcp-hook.js
│ ├── test-natural-triggers.js
│ ├── test-recency-scoring.js
│ ├── tests
│ │ ├── integration-test.js
│ │ ├── phase2-integration-test.js
│ │ ├── test-code-execution.js
│ │ ├── test-cross-session.json
│ │ ├── test-permission-request.js
│ │ ├── test-session-tracking.json
│ │ └── test-threading.json
│ ├── utilities
│ │ ├── adaptive-pattern-detector.js
│ │ ├── auto-capture-patterns.js
│ │ ├── context-formatter.js
│ │ ├── context-shift-detector.js
│ │ ├── conversation-analyzer.js
│ │ ├── dynamic-context-updater.js
│ │ ├── git-analyzer.js
│ │ ├── mcp-client.js
│ │ ├── memory-client.js
│ │ ├── memory-scorer.js
│ │ ├── performance-manager.js
│ │ ├── project-detector.js
│ │ ├── session-cache.json
│ │ ├── session-tracker.js
│ │ ├── tiered-conversation-monitor.js
│ │ ├── user-override-detector.js
│ │ └── version-checker.js
│ └── WINDOWS-SESSIONSTART-BUG.md
├── CLAUDE.md
├── CODE_OF_CONDUCT.md
├── COMMIT_MESSAGE.md
├── CONTRIBUTING.md
├── Development-Sprint-November-2025.md
├── docs
│ ├── amp-cli-bridge.md
│ ├── api
│ │ ├── code-execution-interface.md
│ │ ├── memory-metadata-api.md
│ │ ├── PHASE1_IMPLEMENTATION_SUMMARY.md
│ │ ├── PHASE2_IMPLEMENTATION_SUMMARY.md
│ │ ├── PHASE2_REPORT.md
│ │ └── tag-standardization.md
│ ├── architecture
│ │ ├── graph-database-design.md
│ │ ├── search-enhancement-spec.md
│ │ └── search-examples.md
│ ├── architecture.md
│ ├── archive
│ │ └── obsolete-workflows
│ │ ├── load_memory_context.md
│ │ └── README.md
│ ├── assets
│ │ └── images
│ │ ├── dashboard-v3.3.0-preview.png
│ │ ├── memory-awareness-hooks-example.png
│ │ ├── project-infographic.svg
│ │ └── README.md
│ ├── CLAUDE_CODE_QUICK_REFERENCE.md
│ ├── cloudflare-setup.md
│ ├── demo-recording-script.md
│ ├── deployment
│ │ ├── docker.md
│ │ ├── dual-service.md
│ │ ├── production-guide.md
│ │ └── systemd-service.md
│ ├── development
│ │ ├── ai-agent-instructions.md
│ │ ├── code-quality
│ │ │ ├── phase-2a-completion.md
│ │ │ ├── phase-2a-handle-get-prompt.md
│ │ │ ├── phase-2a-index.md
│ │ │ ├── phase-2a-install-package.md
│ │ │ └── phase-2b-session-summary.md
│ │ ├── code-quality-workflow.md
│ │ ├── dashboard-workflow.md
│ │ ├── issue-management.md
│ │ ├── pr-280-post-mortem.md
│ │ ├── pr-review-guide.md
│ │ ├── refactoring-notes.md
│ │ ├── release-checklist.md
│ │ └── todo-tracker.md
│ ├── docker-optimized-build.md
│ ├── document-ingestion.md
│ ├── DOCUMENTATION_AUDIT.md
│ ├── enhancement-roadmap-issue-14.md
│ ├── examples
│ │ ├── analysis-scripts.js
│ │ ├── maintenance-session-example.md
│ │ ├── memory-distribution-chart.jsx
│ │ ├── quality-system-configs.md
│ │ └── tag-schema.json
│ ├── features
│ │ └── association-quality-boost.md
│ ├── first-time-setup.md
│ ├── glama-deployment.md
│ ├── guides
│ │ ├── advanced-command-examples.md
│ │ ├── chromadb-migration.md
│ │ ├── commands-vs-mcp-server.md
│ │ ├── mcp-enhancements.md
│ │ ├── mdns-service-discovery.md
│ │ ├── memory-consolidation-guide.md
│ │ ├── memory-quality-guide.md
│ │ ├── migration.md
│ │ ├── scripts.md
│ │ └── STORAGE_BACKENDS.md
│ ├── HOOK_IMPROVEMENTS.md
│ ├── hooks
│ │ └── phase2-code-execution-migration.md
│ ├── http-server-management.md
│ ├── ide-compatability.md
│ ├── IMAGE_RETENTION_POLICY.md
│ ├── images
│ │ ├── dashboard-placeholder.md
│ │ └── update-restart-demo.png
│ ├── implementation
│ │ ├── health_checks.md
│ │ └── performance.md
│ ├── IMPLEMENTATION_PLAN_HTTP_SSE.md
│ ├── integration
│ │ ├── homebrew.md
│ │ └── multi-client.md
│ ├── integrations
│ │ ├── gemini.md
│ │ ├── groq-bridge.md
│ │ ├── groq-integration-summary.md
│ │ └── groq-model-comparison.md
│ ├── integrations.md
│ ├── legacy
│ │ └── dual-protocol-hooks.md
│ ├── LIGHTWEIGHT_ONNX_SETUP.md
│ ├── LM_STUDIO_COMPATIBILITY.md
│ ├── maintenance
│ │ └── memory-maintenance.md
│ ├── mastery
│ │ ├── api-reference.md
│ │ ├── architecture-overview.md
│ │ ├── configuration-guide.md
│ │ ├── local-setup-and-run.md
│ │ ├── testing-guide.md
│ │ └── troubleshooting.md
│ ├── migration
│ │ ├── code-execution-api-quick-start.md
│ │ └── graph-migration-guide.md
│ ├── natural-memory-triggers
│ │ ├── cli-reference.md
│ │ ├── installation-guide.md
│ │ └── performance-optimization.md
│ ├── oauth-setup.md
│ ├── pr-graphql-integration.md
│ ├── quality-system-ui-implementation.md
│ ├── quick-setup-cloudflare-dual-environment.md
│ ├── README.md
│ ├── refactoring
│ │ └── phase-3-3-analysis.md
│ ├── releases
│ │ └── v8.72.0-testing.md
│ ├── remote-configuration-wiki-section.md
│ ├── research
│ │ ├── code-execution-interface-implementation.md
│ │ └── code-execution-interface-summary.md
│ ├── ROADMAP.md
│ ├── sqlite-vec-backend.md
│ ├── statistics
│ │ ├── charts
│ │ │ ├── activity_patterns.png
│ │ │ ├── contributors.png
│ │ │ ├── growth_trajectory.png
│ │ │ ├── monthly_activity.png
│ │ │ └── october_sprint.png
│ │ ├── data
│ │ │ ├── activity_by_day.csv
│ │ │ ├── activity_by_hour.csv
│ │ │ ├── contributors.csv
│ │ │ └── monthly_activity.csv
│ │ ├── generate_charts.py
│ │ └── REPOSITORY_STATISTICS.md
│ ├── technical
│ │ ├── development.md
│ │ ├── memory-migration.md
│ │ ├── migration-log.md
│ │ ├── sqlite-vec-embedding-fixes.md
│ │ └── tag-storage.md
│ ├── testing
│ │ └── regression-tests.md
│ ├── testing-cloudflare-backend.md
│ ├── troubleshooting
│ │ ├── cloudflare-api-token-setup.md
│ │ ├── cloudflare-authentication.md
│ │ ├── database-transfer-migration.md
│ │ ├── general.md
│ │ ├── hooks-quick-reference.md
│ │ ├── memory-management.md
│ │ ├── pr162-schema-caching-issue.md
│ │ ├── session-end-hooks.md
│ │ └── sync-issues.md
│ ├── tutorials
│ │ ├── advanced-techniques.md
│ │ ├── data-analysis.md
│ │ └── demo-session-walkthrough.md
│ ├── wiki-documentation-plan.md
│ └── wiki-Graph-Database-Architecture.md
├── examples
│ ├── claude_desktop_config_template.json
│ ├── claude_desktop_config_windows.json
│ ├── claude-desktop-http-config.json
│ ├── config
│ │ └── claude_desktop_config.json
│ ├── http-mcp-bridge.js
│ ├── memory_export_template.json
│ ├── README.md
│ ├── setup
│ │ └── setup_multi_client_complete.py
│ └── start_https_example.sh
├── IMPLEMENTATION_SUMMARY.md
├── install_service.py
├── install.py
├── LICENSE
├── NOTICE
├── PR_DESCRIPTION.md
├── pyproject-lite.toml
├── pyproject.toml
├── pytest.ini
├── README.md
├── release-notes-v8.61.0.md
├── run_server.py
├── scripts
│ ├── .claude
│ │ └── settings.local.json
│ ├── archive
│ │ └── check_missing_timestamps.py
│ ├── backup
│ │ ├── backup_memories.py
│ │ ├── backup_sqlite_vec.sh
│ │ ├── export_distributable_memories.sh
│ │ └── restore_memories.py
│ ├── benchmarks
│ │ ├── benchmark_code_execution_api.py
│ │ ├── benchmark_hybrid_sync.py
│ │ └── benchmark_server_caching.py
│ ├── ci
│ │ ├── check_dockerfile_args.sh
│ │ └── validate_imports.sh
│ ├── database
│ │ ├── analyze_sqlite_vec_db.py
│ │ ├── check_sqlite_vec_status.py
│ │ ├── db_health_check.py
│ │ └── simple_timestamp_check.py
│ ├── development
│ │ ├── debug_server_initialization.py
│ │ ├── find_orphaned_files.py
│ │ ├── fix_mdns.sh
│ │ ├── fix_sitecustomize.py
│ │ ├── remote_ingest.sh
│ │ ├── setup-git-merge-drivers.sh
│ │ ├── uv-lock-merge.sh
│ │ └── verify_hybrid_sync.py
│ ├── hooks
│ │ └── pre-commit
│ ├── installation
│ │ ├── install_linux_service.py
│ │ ├── install_macos_service.py
│ │ ├── install_uv.py
│ │ ├── install_windows_service.py
│ │ ├── install.py
│ │ ├── setup_backup_cron.sh
│ │ ├── setup_claude_mcp.sh
│ │ └── setup_cloudflare_resources.py
│ ├── linux
│ │ ├── service_status.sh
│ │ ├── start_service.sh
│ │ ├── stop_service.sh
│ │ ├── uninstall_service.sh
│ │ └── view_logs.sh
│ ├── maintenance
│ │ ├── add_project_tags.py
│ │ ├── apply_quality_boost_retroactively.py
│ │ ├── assign_memory_types.py
│ │ ├── auto_retag_memory_merge.py
│ │ ├── auto_retag_memory.py
│ │ ├── backfill_graph_table.py
│ │ ├── check_memory_types.py
│ │ ├── cleanup_association_memories_hybrid.py
│ │ ├── cleanup_association_memories.py
│ │ ├── cleanup_corrupted_encoding.py
│ │ ├── cleanup_low_quality.py
│ │ ├── cleanup_memories.py
│ │ ├── cleanup_organize.py
│ │ ├── consolidate_memory_types.py
│ │ ├── consolidation_mappings.json
│ │ ├── delete_orphaned_vectors_fixed.py
│ │ ├── delete_test_memories.py
│ │ ├── fast_cleanup_duplicates_with_tracking.sh
│ │ ├── find_all_duplicates.py
│ │ ├── find_cloudflare_duplicates.py
│ │ ├── find_duplicates.py
│ │ ├── memory-types.md
│ │ ├── README.md
│ │ ├── recover_timestamps_from_cloudflare.py
│ │ ├── regenerate_embeddings.py
│ │ ├── repair_malformed_tags.py
│ │ ├── repair_memories.py
│ │ ├── repair_sqlite_vec_embeddings.py
│ │ ├── repair_zero_embeddings.py
│ │ ├── restore_from_json_export.py
│ │ ├── retag_valuable_memories.py
│ │ ├── scan_todos.sh
│ │ ├── soft_delete_test_memories.py
│ │ └── sync_status.py
│ ├── migration
│ │ ├── cleanup_mcp_timestamps.py
│ │ ├── legacy
│ │ │ └── migrate_chroma_to_sqlite.py
│ │ ├── mcp-migration.py
│ │ ├── migrate_sqlite_vec_embeddings.py
│ │ ├── migrate_storage.py
│ │ ├── migrate_tags.py
│ │ ├── migrate_timestamps.py
│ │ ├── migrate_to_cloudflare.py
│ │ ├── migrate_to_sqlite_vec.py
│ │ ├── migrate_v5_enhanced.py
│ │ ├── TIMESTAMP_CLEANUP_README.md
│ │ └── verify_mcp_timestamps.py
│ ├── pr
│ │ ├── amp_collect_results.sh
│ │ ├── amp_detect_breaking_changes.sh
│ │ ├── amp_generate_tests.sh
│ │ ├── amp_pr_review.sh
│ │ ├── amp_quality_gate.sh
│ │ ├── amp_suggest_fixes.sh
│ │ ├── auto_review.sh
│ │ ├── detect_breaking_changes.sh
│ │ ├── generate_tests.sh
│ │ ├── lib
│ │ │ └── graphql_helpers.sh
│ │ ├── pre_pr_check.sh
│ │ ├── quality_gate.sh
│ │ ├── resolve_threads.sh
│ │ ├── run_pyscn_analysis.sh
│ │ ├── run_quality_checks_on_files.sh
│ │ ├── run_quality_checks.sh
│ │ ├── thread_status.sh
│ │ └── watch_reviews.sh
│ ├── quality
│ │ ├── bulk_evaluate_onnx.py
│ │ ├── check_test_scores.py
│ │ ├── debug_deberta_scoring.py
│ │ ├── export_deberta_onnx.py
│ │ ├── fix_dead_code_install.sh
│ │ ├── migrate_to_deberta.py
│ │ ├── phase1_dead_code_analysis.md
│ │ ├── phase2_complexity_analysis.md
│ │ ├── README_PHASE1.md
│ │ ├── README_PHASE2.md
│ │ ├── rescore_deberta.py
│ │ ├── rescore_fallback.py
│ │ ├── reset_onnx_scores.py
│ │ ├── track_pyscn_metrics.sh
│ │ └── weekly_quality_review.sh
│ ├── README.md
│ ├── run
│ │ ├── memory_wrapper_cleanup.ps1
│ │ ├── memory_wrapper_cleanup.py
│ │ ├── memory_wrapper_cleanup.sh
│ │ ├── README_CLEANUP_WRAPPER.md
│ │ ├── run_mcp_memory.sh
│ │ ├── run-with-uv.sh
│ │ └── start_sqlite_vec.sh
│ ├── run_memory_server.py
│ ├── server
│ │ ├── check_http_server.py
│ │ ├── check_server_health.py
│ │ ├── memory_offline.py
│ │ ├── preload_models.py
│ │ ├── run_http_server.py
│ │ ├── run_memory_server.py
│ │ ├── start_http_server.bat
│ │ └── start_http_server.sh
│ ├── service
│ │ ├── deploy_dual_services.sh
│ │ ├── http_server_manager.sh
│ │ ├── install_http_service.sh
│ │ ├── mcp-memory-http.service
│ │ ├── mcp-memory.service
│ │ ├── memory_service_manager.sh
│ │ ├── service_control.sh
│ │ ├── service_utils.py
│ │ ├── update_service.sh
│ │ └── windows
│ │ ├── add_watchdog_trigger.ps1
│ │ ├── install_scheduled_task.ps1
│ │ ├── manage_service.ps1
│ │ ├── run_http_server_background.ps1
│ │ ├── uninstall_scheduled_task.ps1
│ │ └── update_and_restart.ps1
│ ├── setup-lightweight.sh
│ ├── sync
│ │ ├── check_drift.py
│ │ ├── claude_sync_commands.py
│ │ ├── export_memories.py
│ │ ├── import_memories.py
│ │ ├── litestream
│ │ │ ├── apply_local_changes.sh
│ │ │ ├── enhanced_memory_store.sh
│ │ │ ├── init_staging_db.sh
│ │ │ ├── io.litestream.replication.plist
│ │ │ ├── manual_sync.sh
│ │ │ ├── memory_sync.sh
│ │ │ ├── pull_remote_changes.sh
│ │ │ ├── push_to_remote.sh
│ │ │ ├── README.md
│ │ │ ├── resolve_conflicts.sh
│ │ │ ├── setup_local_litestream.sh
│ │ │ ├── setup_remote_litestream.sh
│ │ │ ├── staging_db_init.sql
│ │ │ ├── stash_local_changes.sh
│ │ │ ├── sync_from_remote_noconfig.sh
│ │ │ └── sync_from_remote.sh
│ │ ├── README.md
│ │ ├── safe_cloudflare_update.sh
│ │ ├── sync_memory_backends.py
│ │ └── sync_now.py
│ ├── testing
│ │ ├── run_complete_test.py
│ │ ├── run_memory_test.sh
│ │ ├── simple_test.py
│ │ ├── test_cleanup_logic.py
│ │ ├── test_cloudflare_backend.py
│ │ ├── test_docker_functionality.py
│ │ ├── test_installation.py
│ │ ├── test_mdns.py
│ │ ├── test_memory_api.py
│ │ ├── test_memory_simple.py
│ │ ├── test_migration.py
│ │ ├── test_search_api.py
│ │ ├── test_sqlite_vec_embeddings.py
│ │ ├── test_sse_events.py
│ │ ├── test-connection.py
│ │ └── test-hook.js
│ ├── update_and_restart.sh
│ ├── utils
│ │ ├── claude_commands_utils.py
│ │ ├── detect_platform.py
│ │ ├── generate_personalized_claude_md.sh
│ │ ├── groq
│ │ ├── groq_agent_bridge.py
│ │ ├── list-collections.py
│ │ ├── memory_wrapper_uv.py
│ │ ├── query_memories.py
│ │ ├── README_detect_platform.md
│ │ ├── smithery_wrapper.py
│ │ ├── test_groq_bridge.sh
│ │ └── uv_wrapper.py
│ └── validation
│ ├── check_dev_setup.py
│ ├── check_documentation_links.py
│ ├── check_handler_coverage.py
│ ├── diagnose_backend_config.py
│ ├── validate_configuration_complete.py
│ ├── validate_graph_tools.py
│ ├── validate_memories.py
│ ├── validate_migration.py
│ ├── validate_timestamp_integrity.py
│ ├── verify_environment.py
│ ├── verify_pytorch_windows.py
│ └── verify_torch.py
├── SECURITY.md
├── selective_timestamp_recovery.py
├── SPONSORS.md
├── src
│ └── mcp_memory_service
│ ├── __init__.py
│ ├── _version.py
│ ├── api
│ │ ├── __init__.py
│ │ ├── client.py
│ │ ├── operations.py
│ │ ├── sync_wrapper.py
│ │ └── types.py
│ ├── backup
│ │ ├── __init__.py
│ │ └── scheduler.py
│ ├── cli
│ │ ├── __init__.py
│ │ ├── ingestion.py
│ │ ├── main.py
│ │ └── utils.py
│ ├── config.py
│ ├── consolidation
│ │ ├── __init__.py
│ │ ├── associations.py
│ │ ├── base.py
│ │ ├── clustering.py
│ │ ├── compression.py
│ │ ├── consolidator.py
│ │ ├── decay.py
│ │ ├── forgetting.py
│ │ ├── health.py
│ │ └── scheduler.py
│ ├── dependency_check.py
│ ├── discovery
│ │ ├── __init__.py
│ │ ├── client.py
│ │ └── mdns_service.py
│ ├── embeddings
│ │ ├── __init__.py
│ │ └── onnx_embeddings.py
│ ├── ingestion
│ │ ├── __init__.py
│ │ ├── base.py
│ │ ├── chunker.py
│ │ ├── csv_loader.py
│ │ ├── json_loader.py
│ │ ├── pdf_loader.py
│ │ ├── registry.py
│ │ ├── semtools_loader.py
│ │ └── text_loader.py
│ ├── lm_studio_compat.py
│ ├── mcp_server.py
│ ├── models
│ │ ├── __init__.py
│ │ └── memory.py
│ ├── quality
│ │ ├── __init__.py
│ │ ├── ai_evaluator.py
│ │ ├── async_scorer.py
│ │ ├── config.py
│ │ ├── implicit_signals.py
│ │ ├── metadata_codec.py
│ │ ├── onnx_ranker.py
│ │ └── scorer.py
│ ├── server
│ │ ├── __init__.py
│ │ ├── __main__.py
│ │ ├── cache_manager.py
│ │ ├── client_detection.py
│ │ ├── environment.py
│ │ ├── handlers
│ │ │ ├── __init__.py
│ │ │ ├── consolidation.py
│ │ │ ├── documents.py
│ │ │ ├── graph.py
│ │ │ ├── memory.py
│ │ │ ├── quality.py
│ │ │ └── utility.py
│ │ └── logging_config.py
│ ├── server_impl.py
│ ├── services
│ │ ├── __init__.py
│ │ └── memory_service.py
│ ├── storage
│ │ ├── __init__.py
│ │ ├── base.py
│ │ ├── cloudflare.py
│ │ ├── factory.py
│ │ ├── graph.py
│ │ ├── http_client.py
│ │ ├── hybrid.py
│ │ ├── migrations
│ │ │ └── 008_add_graph_table.sql
│ │ └── sqlite_vec.py
│ ├── sync
│ │ ├── __init__.py
│ │ ├── exporter.py
│ │ ├── importer.py
│ │ └── litestream_config.py
│ ├── utils
│ │ ├── __init__.py
│ │ ├── cache_manager.py
│ │ ├── content_splitter.py
│ │ ├── db_utils.py
│ │ ├── debug.py
│ │ ├── directory_ingestion.py
│ │ ├── document_processing.py
│ │ ├── gpu_detection.py
│ │ ├── hashing.py
│ │ ├── health_check.py
│ │ ├── http_server_manager.py
│ │ ├── port_detection.py
│ │ ├── quality_analytics.py
│ │ ├── startup_orchestrator.py
│ │ ├── system_detection.py
│ │ └── time_parser.py
│ └── web
│ ├── __init__.py
│ ├── api
│ │ ├── __init__.py
│ │ ├── analytics.py
│ │ ├── backup.py
│ │ ├── consolidation.py
│ │ ├── documents.py
│ │ ├── events.py
│ │ ├── health.py
│ │ ├── manage.py
│ │ ├── mcp.py
│ │ ├── memories.py
│ │ ├── quality.py
│ │ ├── search.py
│ │ └── sync.py
│ ├── app.py
│ ├── dependencies.py
│ ├── oauth
│ │ ├── __init__.py
│ │ ├── authorization.py
│ │ ├── discovery.py
│ │ ├── middleware.py
│ │ ├── models.py
│ │ ├── registration.py
│ │ └── storage.py
│ ├── sse.py
│ └── static
│ ├── app.js
│ ├── i18n
│ │ ├── de.json
│ │ ├── en.json
│ │ ├── es.json
│ │ ├── fr.json
│ │ ├── ja.json
│ │ ├── ko.json
│ │ └── zh.json
│ ├── index.html
│ ├── README.md
│ ├── sse_test.html
│ └── style.css
├── start_http_debug.bat
├── start_http_server.sh
├── test_document.txt
├── test_version_checker.js
├── TESTING_NOTES.md
├── tests
│ ├── __init__.py
│ ├── api
│ │ ├── __init__.py
│ │ ├── test_compact_types.py
│ │ └── test_operations.py
│ ├── bridge
│ │ ├── mock_responses.js
│ │ ├── package-lock.json
│ │ ├── package.json
│ │ └── test_http_mcp_bridge.js
│ ├── conftest.py
│ ├── consolidation
│ │ ├── __init__.py
│ │ ├── conftest.py
│ │ ├── test_associations.py
│ │ ├── test_clustering.py
│ │ ├── test_compression.py
│ │ ├── test_consolidator.py
│ │ ├── test_decay.py
│ │ ├── test_forgetting.py
│ │ └── test_graph_modes.py
│ ├── contracts
│ │ └── api-specification.yml
│ ├── integration
│ │ ├── conftest.py
│ │ ├── HANDLER_COVERAGE_REPORT.md
│ │ ├── package-lock.json
│ │ ├── package.json
│ │ ├── test_all_memory_handlers.py
│ │ ├── test_api_key_fallback.py
│ │ ├── test_api_memories_chronological.py
│ │ ├── test_api_tag_time_search.py
│ │ ├── test_api_with_memory_service.py
│ │ ├── test_bridge_integration.js
│ │ ├── test_cli_interfaces.py
│ │ ├── test_cloudflare_connection.py
│ │ ├── test_concurrent_clients.py
│ │ ├── test_data_serialization_consistency.py
│ │ ├── test_http_server_startup.py
│ │ ├── test_mcp_memory.py
│ │ ├── test_mdns_integration.py
│ │ ├── test_oauth_basic_auth.py
│ │ ├── test_oauth_flow.py
│ │ ├── test_server_handlers.py
│ │ └── test_store_memory.py
│ ├── performance
│ │ ├── test_background_sync.py
│ │ └── test_hybrid_live.py
│ ├── README.md
│ ├── smithery
│ │ └── test_smithery.py
│ ├── sqlite
│ │ └── simple_sqlite_vec_test.py
│ ├── storage
│ │ ├── conftest.py
│ │ └── test_graph_storage.py
│ ├── test_client.py
│ ├── test_content_splitting.py
│ ├── test_database.py
│ ├── test_deberta_quality.py
│ ├── test_fallback_quality.py
│ ├── test_graph_traversal.py
│ ├── test_hybrid_cloudflare_limits.py
│ ├── test_hybrid_storage.py
│ ├── test_lightweight_onnx.py
│ ├── test_memory_ops.py
│ ├── test_memory_wrapper_cleanup.py
│ ├── test_quality_integration.py
│ ├── test_quality_system.py
│ ├── test_semantic_search.py
│ ├── test_sqlite_vec_storage.py
│ ├── test_time_parser.py
│ ├── test_timestamp_preservation.py
│ ├── timestamp
│ │ ├── test_hook_vs_manual_storage.py
│ │ ├── test_issue99_final_validation.py
│ │ ├── test_search_retrieval_inconsistency.py
│ │ ├── test_timestamp_issue.py
│ │ └── test_timestamp_simple.py
│ └── unit
│ ├── conftest.py
│ ├── test_cloudflare_storage.py
│ ├── test_csv_loader.py
│ ├── test_fastapi_dependencies.py
│ ├── test_import.py
│ ├── test_imports.py
│ ├── test_json_loader.py
│ ├── test_mdns_simple.py
│ ├── test_mdns.py
│ ├── test_memory_service.py
│ ├── test_memory.py
│ ├── test_semtools_loader.py
│ ├── test_storage_interface_compatibility.py
│ ├── test_tag_time_filtering.py
│ └── test_uv_no_pip_installer_fallback.py
├── tools
│ ├── docker
│ │ ├── DEPRECATED.md
│ │ ├── docker-compose.http.yml
│ │ ├── docker-compose.pythonpath.yml
│ │ ├── docker-compose.standalone.yml
│ │ ├── docker-compose.uv.yml
│ │ ├── docker-compose.yml
│ │ ├── docker-entrypoint-persistent.sh
│ │ ├── docker-entrypoint-unified.sh
│ │ ├── docker-entrypoint.sh
│ │ ├── Dockerfile
│ │ ├── Dockerfile.glama
│ │ ├── Dockerfile.slim
│ │ ├── README.md
│ │ └── test-docker-modes.sh
│ └── README.md
├── uv.lock
└── verify_compression.sh
```
# Files
--------------------------------------------------------------------------------
/scripts/maintenance/repair_memories.py:
--------------------------------------------------------------------------------
```python
# Copyright 2024 Heinrich Krupp
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# scripts/repair_memories.py
import asyncio
import json
import logging
from mcp_memory_service.storage.chroma import ChromaMemoryStorage
from mcp_memory_service.utils.hashing import generate_content_hash
import argparse
logger = logging.getLogger(__name__)
async def repair_missing_hashes(storage):
"""Repair memories missing content_hash by generating new ones"""
results = storage.collection.get(
include=["metadatas", "documents"]
)
fixed_count = 0
for i, meta in enumerate(results["metadatas"]):
memory_id = results["ids"][i]
if "content_hash" not in meta:
try:
# Generate hash from content and metadata
content = results["documents"][i]
# Create a copy of metadata without the content_hash field
meta_for_hash = {k: v for k, v in meta.items() if k != "content_hash"}
new_hash = generate_content_hash(content, meta_for_hash)
# Update metadata with new hash
new_meta = meta.copy()
new_meta["content_hash"] = new_hash
# Update the memory
storage.collection.update(
ids=[memory_id],
metadatas=[new_meta]
)
logger.info(f"Fixed memory {memory_id} with new hash: {new_hash}")
fixed_count += 1
except Exception as e:
logger.error(f"Error fixing memory {memory_id}: {str(e)}")
return fixed_count
async def main():
log_level = os.getenv('LOG_LEVEL', 'ERROR').upper()
logging.basicConfig(
level=getattr(logging, log_level, logging.ERROR),
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
stream=sys.stderr
)
parser = argparse.ArgumentParser(description='Repair memories with missing content hashes')
parser.add_argument('--db-path', required=True, help='Path to ChromaDB database')
args = parser.parse_args()
logger.info(f"Connecting to database at: {args.db_path}")
storage = ChromaMemoryStorage(args.db_path)
logger.info("Starting repair process...")
fixed_count = await repair_missing_hashes(storage)
logger.info(f"Repair completed. Fixed {fixed_count} memories")
# Run validation again to confirm fixes
logger.info("Running validation to confirm fixes...")
from validate_memories import run_validation_report
report = await run_validation_report(storage)
print("\nPost-repair validation report:")
print(report)
if __name__ == "__main__":
asyncio.run(main())
```
--------------------------------------------------------------------------------
/scripts/quality/export_deberta_onnx.py:
--------------------------------------------------------------------------------
```python
#!/usr/bin/env python3
"""
Export NVIDIA DeBERTa quality classifier to ONNX format.
This script exports the NVIDIA quality-classifier-deberta model
from HuggingFace to ONNX format for local inference.
Usage:
python scripts/quality/export_deberta_onnx.py
The exported model will be cached at:
~/.cache/mcp_memory/onnx_models/nvidia-quality-classifier-deberta/
"""
import sys
import logging
from pathlib import Path
# Add project to path
sys.path.insert(0, str(Path(__file__).parent.parent.parent))
from mcp_memory_service.quality.onnx_ranker import get_onnx_ranker_model
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)
def main():
"""Export NVIDIA DeBERTa to ONNX format."""
print("=" * 80)
print("NVIDIA DeBERTa Quality Classifier - ONNX Export")
print("=" * 80)
print()
logger.info("Initializing DeBERTa model (this will trigger ONNX export if needed)...")
try:
# Create model instance - will automatically export to ONNX if not present
model = get_onnx_ranker_model(
model_name='nvidia-quality-classifier-deberta',
device='cpu' # Use CPU for export (GPU-specific optimizations happen at runtime)
)
if model is None:
logger.error("Failed to create DeBERTa model")
logger.error("Check that you have transformers and torch installed:")
logger.error(" pip install transformers torch onnx onnxruntime")
return 1
# Verify model works with a test inference
logger.info("Testing model with sample input...")
test_content = "This is a high-quality, comprehensive guide with detailed examples and best practices."
test_score = model.score_quality("", test_content) # Empty query for classifier
logger.info(f"Test inference successful! Score: {test_score:.3f}")
print()
print("=" * 80)
print("✅ SUCCESS!")
print("=" * 80)
print()
print(f"Model cached at: {model.MODEL_PATH}")
print(f"Model type: {model.model_config['type']}")
print(f"Model size: {model.model_config['size_mb']}MB")
print()
print("The model is now ready for use.")
print("It will automatically load from cache on subsequent uses.")
print()
print("Next steps:")
print(" 1. Update .env: export MCP_QUALITY_LOCAL_MODEL=nvidia-quality-classifier-deberta")
print(" 2. Restart MCP services")
print(" 3. Run bulk evaluation: python scripts/quality/bulk_evaluate_onnx.py")
return 0
except Exception as e:
logger.error(f"Export failed: {e}", exc_info=True)
print()
print("=" * 80)
print("❌ EXPORT FAILED")
print("=" * 80)
print()
print(f"Error: {e}")
print()
print("Troubleshooting:")
print(" 1. Ensure dependencies are installed: pip install transformers torch onnx onnxruntime")
print(" 2. Check internet connection (model downloads from HuggingFace)")
print(" 3. Verify disk space (~500MB needed for model)")
return 1
if __name__ == '__main__':
sys.exit(main())
```
--------------------------------------------------------------------------------
/claude_commands/memory-ingest-dir.md:
--------------------------------------------------------------------------------
```markdown
# memory-ingest-dir
Batch ingest all supported documents from a directory into the MCP Memory Service database.
## Usage
```
claude /memory-ingest-dir <directory_path> [--tags TAG1,TAG2] [--recursive] [--file-extensions EXT1,EXT2] [--chunk-size SIZE] [--chunk-overlap SIZE] [--max-files COUNT]
```
## Parameters
- `directory_path`: Path to the directory containing documents to ingest (required)
- `--tags`: Comma-separated list of tags to apply to all memories created
- `--recursive`: Process subdirectories recursively (default: true)
- `--file-extensions`: Comma-separated list of file extensions to process (default: pdf,txt,md,json)
- `--chunk-size`: Target size for text chunks in characters (default: 1000)
- `--chunk-overlap`: Characters to overlap between chunks (default: 200)
- `--max-files`: Maximum number of files to process (default: 100)
## Supported Formats
- PDF files (.pdf)
- Text files (.txt, .md, .markdown, .rst)
- JSON files (.json)
## Implementation
I need to upload multiple documents from a directory to the MCP Memory Service HTTP API endpoint.
First, let me check if the service is running and find all supported files in the directory:
```bash
# Check if the service is running
curl -s http://localhost:8080/api/health || curl -s http://localhost:8443/api/health || echo "Service not running"
# Find supported files in the directory
find "$DIRECTORY_PATH" -type f \( -iname "*.pdf" -o -iname "*.txt" -o -iname "*.md" -o -iname "*.json" \) | head -n $MAX_FILES
```
Then I'll upload the files in batch:
```bash
# Create a temporary script to upload files
UPLOAD_SCRIPT=$(mktemp)
cat > "$UPLOAD_SCRIPT" << 'EOF'
#!/bin/bash
TAGS="$1"
CHUNK_SIZE="$2"
CHUNK_OVERLAP="$3"
MAX_FILES="$4"
shift 4
FILES=("$@")
for file in "${FILES[@]}"; do
echo "Uploading: $file"
curl -X POST "http://localhost:8080/api/documents/upload" \
-F "file=@$file" \
-F "tags=$TAGS" \
-F "chunk_size=$CHUNK_SIZE" \
-F "chunk_overlap=$CHUNK_OVERLAP" \
-F "memory_type=document"
echo ""
done
EOF
chmod +x "$UPLOAD_SCRIPT"
```
## Examples
```
# Ingest all PDFs from a directory
claude /memory-ingest-dir ./docs --file-extensions pdf --tags documentation
# Recursively ingest from knowledge base
claude /memory-ingest-dir ./knowledge-base --recursive --tags knowledge,reference
# Limit processing to specific formats
claude /memory-ingest-dir ./articles --file-extensions md,txt --max-files 50 --tags articles
```
## Actual Execution Steps
When you run this command, I will:
1. **Scan the directory** for supported file types (PDF, TXT, MD, JSON)
2. **Apply filtering** based on file extensions and max files limit
3. **Validate the service** is running and accessible
4. **Upload files in batch** using the documents API endpoint
5. **Monitor progress** for each file and show real-time updates
6. **Report results** including total chunks created and any errors
All documents will be processed with consistent tagging and chunking parameters.
## Notes
- Files are processed in parallel for efficiency
- Progress is displayed with file counts and chunk statistics
- Each document gets processed independently - failures in one don't stop others
- Automatic tagging includes source directory and file type information
- Large directories may take time - consider using --max-files for testing
```
--------------------------------------------------------------------------------
/tests/timestamp/test_timestamp_simple.py:
--------------------------------------------------------------------------------
```python
#!/usr/bin/env python3
"""Test script to debug timestamp issues in recall functionality."""
import time
from datetime import datetime, timedelta
def test_timestamp_precision():
"""Test timestamp storage and retrieval issues."""
print("=== Testing Timestamp Precision Issue ===")
# Test 1: Precision loss when converting float to int
print("\n1. Testing precision loss:")
current_time = time.time()
print(f"Current time (float): {current_time}")
print(f"Current time (int): {int(current_time)}")
print(f"Difference: {current_time - int(current_time)} seconds")
# Test 2: Edge case demonstration
print("\n2. Testing edge case with timestamps:")
# Create timestamps for yesterday at midnight
today = datetime.now().replace(hour=0, minute=0, second=0, microsecond=0)
yesterday_start = (today - timedelta(days=1)).timestamp()
yesterday_end = (today - timedelta(microseconds=1)).timestamp()
print(f"\nYesterday range:")
print(f" Start (float): {yesterday_start} ({datetime.fromtimestamp(yesterday_start)})")
print(f" End (float): {yesterday_end} ({datetime.fromtimestamp(yesterday_end)})")
print(f" Start (int): {int(yesterday_start)}")
print(f" End (int): {int(yesterday_end)}")
# Test a memory created at various times yesterday
test_times = [
("00:00:00.5", yesterday_start + 0.5),
("00:00:30", yesterday_start + 30),
("12:00:00", yesterday_start + 12*3600),
("23:59:59.5", yesterday_end - 0.5)
]
print("\n3. Testing memory inclusion with float vs int comparison:")
for time_desc, timestamp in test_times:
print(f"\n Memory at {time_desc} (timestamp: {timestamp}):")
# Float comparison
float_included = (timestamp >= yesterday_start and timestamp <= yesterday_end)
print(f" Float comparison: {float_included}")
# Int comparison (current implementation)
int_included = (int(timestamp) >= int(yesterday_start) and int(timestamp) <= int(yesterday_end))
print(f" Int comparison: {int_included}")
if float_included != int_included:
print(f" ⚠️ MISMATCH! Memory would be {'excluded' if float_included else 'included'} incorrectly!")
# Test 4: Demonstrate the issue with ChromaDB filtering
print("\n4. ChromaDB filter comparison issue:")
print(" ChromaDB uses integer comparisons for numeric fields.")
print(" When we store timestamp as int(created_at), we lose sub-second precision.")
print(" This can cause memories to be excluded from time-based queries.")
# Example of the fix
print("\n5. Proposed fix:")
print(" Option 1: Store timestamp as float in metadata (if ChromaDB supports it)")
print(" Option 2: Store timestamp with higher precision (e.g., milliseconds as int)")
print(" Option 3: Use ISO string timestamps for filtering")
# Test millisecond precision
print("\n6. Testing millisecond precision:")
current_ms = int(current_time * 1000)
print(f" Current time in ms: {current_ms}")
print(f" Reconstructed time: {current_ms / 1000}")
print(f" Precision preserved: {abs((current_ms / 1000) - current_time) < 0.001}")
if __name__ == "__main__":
test_timestamp_precision()
```
--------------------------------------------------------------------------------
/tests/test_database.py:
--------------------------------------------------------------------------------
```python
"""
MCP Memory Service
Copyright (c) 2024 Heinrich Krupp
Licensed under the MIT License. See LICENSE file in the project root for full license text.
"""
"""
Test database operations of the MCP Memory Service.
"""
import pytest
import pytest_asyncio
import asyncio
import os
from mcp_memory_service.server import MemoryServer
@pytest_asyncio.fixture
async def memory_server():
"""Create a test instance of the memory server."""
server = MemoryServer()
# MemoryServer initializes itself, no initialize() call needed
yield server
# No cleanup needed - MemoryServer doesn't have shutdown()
@pytest.mark.asyncio
async def test_create_backup(memory_server):
"""Test database backup creation."""
# Store some test data
await memory_server.store_memory(
content="Test memory for backup"
)
# Create backup
backup_response = await memory_server.create_backup()
assert backup_response.get("success") is True
assert backup_response.get("backup_path") is not None
assert os.path.exists(backup_response.get("backup_path"))
@pytest.mark.asyncio
async def test_database_health(memory_server):
"""Test database health check functionality."""
health_status = await memory_server.check_database_health()
assert health_status is not None
assert "status" in health_status
assert "memory_count" in health_status
assert "database_size" in health_status
@pytest.mark.asyncio
async def test_optimize_database(memory_server):
"""Test database optimization."""
# Store multiple memories to trigger optimization
for i in range(10):
await memory_server.store_memory(
content=f"Test memory {i}"
)
# Run optimization
optimize_response = await memory_server.optimize_db()
assert optimize_response.get("success") is True
assert "optimized_size" in optimize_response
@pytest.mark.skip(reason="Issue #316: wandb.proto dependency broken - 'module wandb.proto.wandb_internal_pb2 has no attribute Result'")
@pytest.mark.asyncio
async def test_cleanup_duplicates(memory_server):
"""Test duplicate memory cleanup."""
# Store duplicate memories
duplicate_content = "This is a duplicate memory"
await memory_server.store_memory(content=duplicate_content)
await memory_server.store_memory(content=duplicate_content)
# Clean up duplicates
cleanup_response = await memory_server.cleanup_duplicates()
assert cleanup_response.get("success") is True
assert cleanup_response.get("duplicates_removed") >= 1
# Verify only one copy remains
results = await memory_server.exact_match_retrieve(
content=duplicate_content
)
assert len(results) == 1
@pytest.mark.asyncio
async def test_database_persistence(memory_server):
"""Test database persistence across server restarts."""
test_content = "Persistent memory test"
# Store memory
await memory_server.store_memory(content=test_content)
# Simulate server restart
await memory_server.shutdown()
# Create new server instance to simulate restart
new_server = MemoryServer()
# Verify memory persists
results = await new_server.exact_match_retrieve(
content=test_content
)
assert len(results) == 1
assert results[0] == test_content
# No cleanup needed
```
--------------------------------------------------------------------------------
/run_server.py:
--------------------------------------------------------------------------------
```python
#!/usr/bin/env python3
"""Run the MCP Memory Service with HTTP/HTTPS/mDNS support via FastAPI."""
import os
import sys
import uvicorn
import logging
# Add src to path
sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'src'))
# Set up logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
if __name__ == "__main__":
# Log configuration
logger.info("Starting MCP Memory Service FastAPI server with the following configuration:")
logger.info(f" Storage Backend: {os.environ.get('MCP_MEMORY_STORAGE_BACKEND', 'sqlite_vec')}")
logger.info(f" HTTP Port: {os.environ.get('MCP_HTTP_PORT', '8000')}")
logger.info(f" HTTPS Enabled: {os.environ.get('MCP_HTTPS_ENABLED', 'false')}")
logger.info(f" HTTPS Port: {os.environ.get('MCP_HTTPS_PORT', '8443')}")
logger.info(f" mDNS Enabled: {os.environ.get('MCP_MDNS_ENABLED', 'false')}")
logger.info(f" API Key Set: {'Yes' if os.environ.get('MCP_API_KEY') else 'No'}")
http_port = int(os.environ.get('MCP_HTTP_PORT', 8000))
# Check if HTTPS is enabled
if os.environ.get('MCP_HTTPS_ENABLED', 'false').lower() == 'true':
https_port = int(os.environ.get('MCP_HTTPS_PORT', 8443))
# Check for environment variable certificates first
cert_file = os.environ.get('MCP_SSL_CERT_FILE')
key_file = os.environ.get('MCP_SSL_KEY_FILE')
if cert_file and key_file:
# Use provided certificates
if not os.path.exists(cert_file):
logger.error(f"Certificate file not found: {cert_file}")
sys.exit(1)
if not os.path.exists(key_file):
logger.error(f"Key file not found: {key_file}")
sys.exit(1)
logger.info(f"Using provided certificates: {cert_file}")
else:
# Generate self-signed certificate if needed
cert_dir = os.path.expanduser("~/.mcp_memory_certs")
os.makedirs(cert_dir, exist_ok=True)
cert_file = os.path.join(cert_dir, "cert.pem")
key_file = os.path.join(cert_dir, "key.pem")
if not os.path.exists(cert_file) or not os.path.exists(key_file):
logger.info("Generating self-signed certificate for HTTPS...")
import subprocess
subprocess.run([
"openssl", "req", "-x509", "-newkey", "rsa:4096",
"-keyout", key_file, "-out", cert_file,
"-days", "365", "-nodes",
"-subj", "/C=US/ST=State/L=City/O=MCP/CN=localhost"
], check=True)
logger.info(f"Certificate generated at {cert_dir}")
# Run with HTTPS
logger.info(f"Starting HTTPS server on port {https_port}")
uvicorn.run(
"mcp_memory_service.web.app:app",
host="0.0.0.0",
port=https_port,
ssl_keyfile=key_file,
ssl_certfile=cert_file,
reload=False,
log_level="info"
)
else:
# Run HTTP only
logger.info(f"Starting HTTP server on port {http_port}")
uvicorn.run(
"mcp_memory_service.web.app:app",
host="0.0.0.0",
port=http_port,
reload=False,
log_level="info"
)
```
--------------------------------------------------------------------------------
/tools/docker/Dockerfile:
--------------------------------------------------------------------------------
```dockerfile
## Slim (CPU-only) Docker image optimized for sqlite-vec + ONNX
## Consolidated as the primary Dockerfile to avoid confusion.
FROM python:3.12-slim
# Build arguments for conditional features
ARG SKIP_MODEL_DOWNLOAD=false
ARG INSTALL_EXTRA="[sqlite]"
ARG FORCE_CPU_PYTORCH=false
# Set environment variables
ENV PYTHONUNBUFFERED=1 \
MCP_MEMORY_STORAGE_BACKEND=sqlite_vec \
MCP_MEMORY_SQLITE_PATH=/app/sqlite_db \
MCP_MEMORY_BACKUPS_PATH=/app/backups \
PYTHONPATH=/app/src \
DOCKER_CONTAINER=1 \
CHROMA_TELEMETRY_IMPL=none \
ANONYMIZED_TELEMETRY=false \
HF_HUB_DISABLE_TELEMETRY=1
# Set the working directory
WORKDIR /app
# Minimal system packages with security updates
# hadolint ignore=DL3008
RUN apt-get update && \
apt-get install -y --no-install-recommends \
curl \
bash \
&& apt-get upgrade -y \
&& rm -rf /var/lib/apt/lists/* \
&& apt-get clean
# Copy essential files, install UV, and create directories
COPY pyproject.toml .
COPY uv.lock .
COPY README.md .
COPY scripts/installation/install_uv.py .
RUN python install_uv.py && \
mkdir -p /app/sqlite_db /app/backups
# Copy source code
COPY src/ /app/src/
COPY run_server.py ./
# Copy utility scripts if they exist
COPY scripts/utils/uv_wrapper.py ./uv_wrapper.py
COPY scripts/utils/memory_wrapper_uv.py ./memory_wrapper_uv.py
# Copy Docker entrypoint scripts
COPY tools/docker/docker-entrypoint.sh /usr/local/bin/
COPY tools/docker/docker-entrypoint-persistent.sh /usr/local/bin/
COPY tools/docker/docker-entrypoint-unified.sh /usr/local/bin/
# Install the package with UV (configurable dependency group)
# Use CPU-only PyTorch by default to save disk space in CI/test environments
RUN if [ "$FORCE_CPU_PYTORCH" = "true" ] || [ "$INSTALL_EXTRA" = "[sqlite]" ]; then \
echo "Installing CPU-only PyTorch to save disk space..."; \
python -m uv pip install torch --index-url https://download.pytorch.org/whl/cpu; \
python -m uv pip install -e .${INSTALL_EXTRA}; \
else \
python -m uv pip install -e .${INSTALL_EXTRA}; \
fi
# Conditionally pre-download ONNX models for lightweight embedding
RUN if [ "$SKIP_MODEL_DOWNLOAD" != "true" ]; then \
echo "Pre-downloading ONNX embedding models..." && \
python -c "try:\
import onnxruntime as ort; \
print('ONNX runtime available for lightweight embeddings'); \
print('ONNX models will be downloaded at runtime as needed')\
except Exception as e:\
print(f'Warning: ONNX runtime not available: {e}'); \
print('Embedding functionality may be limited')" || echo "ONNX check failed, continuing..."; \
else \
echo "Skipping model download (SKIP_MODEL_DOWNLOAD=true)"; \
fi
# Configure stdio for MCP communication and make entrypoints executable
RUN chmod a+rw /dev/stdin /dev/stdout /dev/stderr && \
chmod +x /usr/local/bin/docker-entrypoint.sh && \
chmod +x /usr/local/bin/docker-entrypoint-persistent.sh && \
chmod +x /usr/local/bin/docker-entrypoint-unified.sh
# Add volume mount points for data persistence
VOLUME ["/app/sqlite_db", "/app/backups"]
# Expose the port (if needed)
EXPOSE 8000
# Use the unified entrypoint script by default
# Can be overridden with docker-entrypoint.sh for backward compatibility
ENTRYPOINT ["/usr/local/bin/docker-entrypoint-unified.sh"]
```
--------------------------------------------------------------------------------
/archive/docs-removed-2025-08-23/claude-desktop-setup.md:
--------------------------------------------------------------------------------
```markdown
# Claude Desktop Setup Guide - Windows
This guide helps you configure the MCP Memory Service to work with Claude Desktop on Windows without repeated PyTorch downloads.
## Problem and Solution
**Issue**: Claude Desktop was downloading PyTorch models (230MB+) on every startup due to missing offline configuration.
**Solution**: Added offline mode environment variables to your Claude Desktop config to use cached models.
## What Was Fixed
✅ **Your Claude Desktop Config Updated**:
- Added offline mode environment variables (`HF_HUB_OFFLINE=1`, `TRANSFORMERS_OFFLINE=1`)
- Added cache path configurations
- Kept your existing SQLite-vec backend setup
✅ **Verified Components Working**:
- SQLite-vec database: 434 memories accessible ✅
- sentence-transformers: Loading models without downloads ✅
- Offline mode: No network requests when properly configured ✅
## Current Working Configuration
Your active config at `%APPDATA%\Claude\claude_desktop_config.json` now has:
- **Backend**: SQLite-vec (single database file)
- **Database**: `memory_migrated.db` with 434 memories
- **Offline Mode**: Enabled to prevent downloads
- **UV Package Manager**: For better dependency management
## For Other Users
See `examples/claude_desktop_config_windows.json` for an anonymized template with:
- SQLite-vec backend configuration (recommended)
- ChromaDB alternative configuration
- Offline mode settings
- Performance optimizations
Replace `YOUR_USERNAME` with your actual Windows username.
## Key Changes Made
### 1. Config Template Updates
- Removed `PYTHONNOUSERSITE=1`, `PIP_NO_DEPENDENCIES=1`, `PIP_NO_INSTALL=1`
- These were blocking access to globally installed packages
### 2. Server Path Detection
Enhanced `src/mcp_memory_service/server.py`:
- Better virtual environment detection
- Windows-specific path handling
- Global site-packages access when not blocked
### 3. Dependency Checking
Improved `src/mcp_memory_service/dependency_check.py`:
- Enhanced model cache detection for Windows
- Better first-run detection logic
- Multiple cache location checking
### 4. Storage Backend Fixes
Updated both ChromaDB and SQLite-vec storage:
- Fixed hardcoded Linux paths
- Added offline mode configuration
- Better cache path detection
## Verification
After updating your Claude Desktop config:
1. **Restart Claude Desktop** completely
2. **Check the logs** - you should see:
```
✅ All dependencies are installed
DEBUG: Found cached model in C:\Users\[username]\.cache\huggingface\hub
```
3. **No more downloads** - The 230MB PyTorch download should not occur
## Testing
You can test the server directly:
```bash
python scripts/run_memory_server.py --debug
```
You should see dependency checking passes and models load from cache.
## Troubleshooting
If you still see downloads:
1. Verify your username in the config paths
2. Check that models exist in `%USERPROFILE%\.cache\huggingface\hub`
3. Ensure Claude Desktop has been fully restarted
## Files Modified
- `examples/claude_desktop_config_template.json` - Removed blocking env vars
- `examples/claude_desktop_config_windows.json` - New Windows-specific config
- `src/mcp_memory_service/server.py` - Enhanced path detection
- `src/mcp_memory_service/dependency_check.py` - Better cache detection
- `src/mcp_memory_service/storage/sqlite_vec.py` - Fixed hardcoded paths
- `src/mcp_memory_service/storage/chroma.py` - Added offline mode support
```
--------------------------------------------------------------------------------
/.github/workflows/claude.yml:
--------------------------------------------------------------------------------
```yaml
name: Claude Code
on:
issue_comment:
types: [created]
pull_request_review_comment:
types: [created]
issues:
types: [opened, assigned]
pull_request_review:
types: [submitted]
jobs:
claude:
if: |
(github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude') && github.event.comment.user.login == github.repository_owner) ||
(github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude') && github.event.comment.user.login == github.repository_owner) ||
(github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude') && github.event.review.user.login == github.repository_owner) ||
(github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude')) && github.event.issue.user.login == github.repository_owner)
runs-on: ubuntu-latest
permissions:
contents: write # Allow creating branches and commits
pull-requests: write # Allow posting PR comments and reviews
issues: write # Allow posting issue comments
id-token: write
actions: read # Required for Claude to read CI results on PRs
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 1
- name: Run Claude Code
id: claude
uses: anthropics/claude-code-action@v1
with:
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
# Enable sticky comments for PRs only
use_sticky_comment: true
# Allow Claude to post comments on issues and PRs using gh CLI
claude_args: '--allowed-tools "Bash(gh issue comment:*),Bash(gh pr comment:*),Bash(gh issue view:*),Bash(gh pr view:*)"'
# This is an optional setting that allows Claude to read CI results on PRs
additional_permissions: |
actions: read
# Auto-invoke github-release-manager agent for bug fixes and features
# This triggers release workflow when Claude fixes issues on GitHub
prompt: |
${{ github.event.comment.body || github.event.issue.body || github.event.review.body }}
IMPORTANT: After you complete the task, post your response using:
- For issues: Use `gh issue comment <issue_number> --body "your response"`
- For PRs: Use `gh pr comment <pr_number> --body "your response"`
The issue/PR number is available in the GitHub context.
IMPORTANT: After completing the requested task, if you:
1. Fixed a bug (modified src/ code)
2. Added a new feature (modified src/ code)
3. Made any changes to pyproject.toml dependencies
Then automatically invoke the github-release-manager agent to:
- Determine appropriate version bump (patch for fixes, minor for features)
- Create release branch with version updates
- The Claude Branch Automation workflow will handle the rest
Skip release manager if you only changed:
- Documentation (.md files, docs/)
- Tests only (tests/ without src/ changes)
- CI/CD workflows (.github/)
- Development tools (.claude/)
Use your judgment - if unsure whether to release, ask the user.
```
--------------------------------------------------------------------------------
/archive/docs-removed-2025-08-23/development/TIMESTAMP_FIX_SUMMARY.md:
--------------------------------------------------------------------------------
```markdown
# Timestamp Recall Fix Summary
## Issue Description
The memory recall functionality in mcp-memory-service was experiencing issues with timestamp-based queries. Memories stored with precise timestamps (including sub-second precision) were being retrieved incorrectly or not at all when using time-based recall functions.
## Root Cause
The issue was caused by timestamps being converted to integers at multiple points in the codebase:
1. **Storage**: In `ChromaMemoryStorage._optimize_metadata_for_chroma()`, timestamps were being stored as `int(memory.created_at)`
2. **Querying**: In the `recall()` method, timestamp comparisons were using `int(start_timestamp)` and `int(end_timestamp)`
3. **Memory Model**: In `Memory.to_dict()`, the timestamp field was being converted to `int(self.created_at)`
This integer conversion caused loss of sub-second precision, making all memories within the same second indistinguishable by timestamp.
## Changes Made
### 1. Fixed Timestamp Storage (chroma.py)
Changed line 949 in `_optimize_metadata_for_chroma()`:
```python
# Before:
"timestamp": int(memory.created_at),
# After:
"timestamp": float(memory.created_at), # Changed from int() to float()
```
### 2. Fixed Timestamp Queries (chroma.py)
Changed lines 739 and 743 in the `recall()` method:
```python
# Before:
where_clause["$and"].append({"timestamp": {"$gte": int(start_timestamp)}})
where_clause["$and"].append({"timestamp": {"$lte": int(end_timestamp)}})
# After:
where_clause["$and"].append({"timestamp": {"$gte": float(start_timestamp)}})
where_clause["$and"].append({"timestamp": {"$lte": float(end_timestamp)}})
```
### 3. Fixed Memory Model (memory.py)
Changed line 161 in `Memory.to_dict()`:
```python
# Before:
"timestamp": int(self.created_at), # Legacy timestamp (int)
# After:
"timestamp": float(self.created_at), # Changed from int() to preserve precision
```
### 4. Fixed Date Parsing Order (time_parser.py)
Moved the full ISO date pattern check before the specific date pattern check to prevent "2024-06-15" from being incorrectly parsed as "24-06-15".
## Tests Added
### 1. Timestamp Recall Tests (`tests/test_timestamp_recall.py`)
- Tests for timestamp precision storage
- Tests for natural language time parsing
- Tests for various recall scenarios (yesterday, last week, specific dates)
- Tests for combined semantic and time-based recall
- Edge case tests
### 2. Time Parser Tests (`tests/test_time_parser.py`)
- Comprehensive tests for all supported time expressions
- Tests for relative dates (yesterday, 3 days ago, last week)
- Tests for specific date formats (MM/DD/YYYY, YYYY-MM-DD)
- Tests for seasons, holidays, and named periods
- Tests for time extraction from queries
## Verification
The fix has been verified with:
1. Unit tests covering individual components
2. Integration tests demonstrating end-to-end functionality
3. Precision tests showing that sub-second timestamps are now preserved
## Impact
- Memories can now be recalled with precise timestamp filtering
- Sub-second precision is maintained throughout storage and retrieval
- Natural language time expressions work correctly
- No breaking changes to existing functionality
## Recommendations
1. Consider adding database migration for existing memories with integer timestamps
2. Monitor performance impact of float vs integer comparisons in large datasets
3. Add documentation about supported time expressions for users
```
--------------------------------------------------------------------------------
/.github/workflows/LATEST_FIXES.md:
--------------------------------------------------------------------------------
```markdown
# Latest Workflow Fixes (2024-08-24)
## Issues Resolved
### 1. Workflow Conflicts
**Problem**: Both `main.yml` and `main-optimized.yml` running simultaneously with same triggers, concurrency groups, and job names.
**Solution**:
- Temporarily disabled `main.yml` → `main.yml.disabled`
- Allows `main-optimized.yml` to run without conflicts
### 2. Matrix Strategy Failures
**Problem**: Matrix jobs failing fast, stopping entire workflow on single failure.
**Solutions Applied**:
- Added `fail-fast: false` to both test and publish-docker matrix strategies
- Allows other matrix combinations to continue even if one fails
- Improved fault tolerance
### 3. Missing Debugging Information
**Problem**: Workflow failures lacked context about what exactly was failing.
**Solutions Applied**:
- Added comprehensive debugging steps to test jobs
- Environment information logging (Python version, disk space, etc.)
- File system validation before operations
- Progress indicators with emojis for better visibility
### 4. Poor Error Handling
**Problem**: Jobs failed completely on minor issues, preventing workflow completion.
**Solutions Applied**:
- Added `continue-on-error: true` to optional steps
- Improved conditional logic for Docker Hub authentication
- Better fallback handling for missing test directories
- More informative error messages
### 5. Dependency Issues
**Problem**: Jobs failing due to missing files, credentials, or dependencies.
**Solutions Applied**:
- Added pre-flight checks for required files (Dockerfile, src/, pyproject.toml)
- Enhanced credential validation
- Created fallback test when test directory missing
- Improved job dependency conditions
## Specific Changes Made
### main-optimized.yml
```yaml
# Added debugging
- name: Debug environment
run: |
echo "🐍 Python version: $(python --version)"
# ... more debug info
# Fixed matrix strategies
strategy:
fail-fast: false # ← Key addition
matrix:
# ... existing matrix
# Enhanced test steps with validation
- name: Run unit tests
if: matrix.test-type == 'unit'
run: |
echo "🧪 Starting unit tests..."
# ... detailed steps with error handling
# Improved Docker build validation
- name: Check Docker requirements
run: |
echo "🐳 Checking Docker build requirements..."
# ... file validation
```
### File Changes
- `main.yml` → `main.yml.disabled` (temporary)
- Enhanced error handling in both workflows
- Added comprehensive debugging throughout
## Expected Improvements
1. **Workflow Stability**: No more conflicts between competing workflows
2. **Better Diagnostics**: Clear logging shows where issues occur
3. **Fault Tolerance**: Individual job failures don't stop entire workflow
4. **Graceful Degradation**: Missing credentials/dependencies handled elegantly
5. **Developer Experience**: Emojis and clear messages improve log readability
## Testing Strategy
1. **Immediate**: Push changes trigger main-optimized.yml only
2. **Monitor**: Watch for improved error messages and debugging info
3. **Validate**: Ensure matrix jobs complete independently
4. **Rollback**: Original main.yml available if needed
## Success Metrics
- ✅ Workflows complete without conflicts
- ✅ Matrix jobs show individual results
- ✅ Clear error messages when issues occur
- ✅ Graceful handling of missing credentials
- ✅ Debugging information helps troubleshoot future issues
Date: 2024-08-24
Status: Applied and ready for testing
```
--------------------------------------------------------------------------------
/archive/docs-removed-2025-08-23/development/CLEANUP_SUMMARY.md:
--------------------------------------------------------------------------------
```markdown
# 🧹 MCP-Memory-Service Cleanup Summary
**Date:** June 7, 2025
**Operation:** Artifact Cleanup & Reorganization
## 📊 **Cleanup Statistics**
### **Files Archived:**
- **Memory Service**: 11 test/debug files → `/archive/`
- **Dashboard**: 37 test/debug files → `/archive/test-files/`
- **Total**: 48 obsolete artifacts safely preserved
### **Backups Created:**
- `mcp-memory-service-backup-20250607-0705.tar.gz` (193MB)
- `mcp-memory-dashboard-backup-20250607-0706.tar.gz` (215MB)
## 🗂️ **Files Moved to Archive**
### **Memory Service (`/archive/`):**
```
alternative_test_server.py
compatibility_test_server.py
diagnose_mcp.py
fixed_memory_server.py
memory_wrapper.py
memory_wrapper_uv.py
minimal_uv_server.py
simplified_memory_server.py
test_client.py
ultimate_protocol_debug.py
uv_wrapper.py
```
### **Dashboard (`/archive/test-files/`):**
```
All test_*.js files (20+ files)
All test_*.py files (5+ files)
All test_*.sh files (5+ files)
*_minimal_server.py files
investigation.js & investigation_report.json
comprehensive_*test* files
final_*test* files
```
### **Dashboard (`/archive/`):**
```
CLAUDE_INTEGRATION_TEST.md
INTEGRATION_ACTION_PLAN.md
RESTORATION_COMPLETE.md
investigation.js
investigation_report.json
ultimate_investigation.js
ultimate_investigation.sh
```
## ✅ **Post-Cleanup Verification**
### **Memory Service Status:**
- ✅ Database Health: HEALTHY
- ✅ Total Memories: 164 (increased from previous 162)
- ✅ Storage: 8.36 MB
- ✅ Dashboard Integration: WORKING
- ✅ Core Operations: ALL FUNCTIONAL
### **Tests Performed:**
1. Database health check ✅
2. Dashboard health check ✅
3. Memory storage operation ✅
4. Memory retrieval operation ✅
## 🎯 **Production Files Preserved**
### **Memory Service Core:**
- `src/mcp_memory_service/server.py` - Main server
- `src/mcp_memory_service/server copy.py` - **CRITICAL BACKUP**
- All core implementation files
- Configuration files (pyproject.toml, etc.)
- Documentation (README.md, CHANGELOG.md)
### **Dashboard Core:**
- `src/` directory - Main dashboard implementation
- Configuration files (package.json, vite.config.ts, etc.)
- Build scripts and deployment files
## 📁 **Directory Structure (Cleaned)**
### **Memory Service:**
```
mcp-memory-service/
├── src/mcp_memory_service/ # Core implementation
├── scripts/ # Utility scripts
├── tests/ # Test suite
├── archive/ # Archived test artifacts
├── pyproject.toml # Project config
├── requirements.txt # Dependencies
└── README.md # Documentation
```
### **Dashboard:**
```
mcp-memory-dashboard/
├── src/ # Core dashboard
├── dist/ # Built files
├── archive/ # Archived test artifacts
├── package.json # Project config
├── vite.config.ts # Build config
└── README.md # Documentation
```
## 🔒 **Safety Measures**
1. **Full backups created** before any file operations
2. **Archives created** instead of deletion (nothing lost)
3. **Critical files preserved** (especially `server copy.py`)
4. **Functionality verified** after cleanup
5. **Production code untouched**
## 📝 **Next Steps**
1. ✅ Memory service cleanup complete
2. 🔄 Dashboard integration testing (next phase)
3. 🎯 Focus on remaining dashboard issues
4. 📊 Performance optimization if needed
---
**Result: Clean, organized codebase with all production functionality intact! 🚀**
```
--------------------------------------------------------------------------------
/.claude/directives/memory-first.md:
--------------------------------------------------------------------------------
```markdown
# Information Retrieval Directive
## RULE: Layered Information Lookup
When you need information about this project, follow this order:
### 1. Files First (Source of Truth)
**Always check files before anything else:**
- **Code**: `src/`, `tests/`, `scripts/`
- **Docs**: `docs/`, `CHANGELOG.md`, `README.md`
- **Config**: `.env`, `pyproject.toml`, `.claude/directives/`
**Why**: Files are always current. Code doesn't lie. Documentation may lag, but code is truth.
**Examples:**
- How does X work? → Read the implementation
- What's the current API? → Check the code
- What's configured? → Read config files
### 2. Memory Second (Historical Context)
**Search memory when files don't explain WHY:**
Use `mcp__memory__retrieve_memory(query)` for:
- **Design decisions**: Why was X chosen over Y?
- **Known issues**: Has this problem been solved before?
- **Performance baselines**: What metrics did we measure?
- **Release history**: What changed and why?
- **Learnings**: What mistakes did we make?
**Common search patterns:**
```bash
# Design decisions
mcp__memory__retrieve_memory("consolidation design decision")
# Known issues
mcp__memory__search_by_tag(["bug-fix", "troubleshooting"])
# Performance context
mcp__memory__retrieve_memory("performance baseline measurements")
```
**Tags to search**: `mcp-memory-service`, `architecture`, `decision`, `bug-fix`, `performance`, `release`
### 3. User Last (Genuine Unknowns)
**Only ask the user when:**
- Files don't contain the information
- Memory has no relevant context
- User preference or decision is genuinely needed
- Ambiguity requires clarification
**Don't ask when:**
- The answer is in the code (read it first!)
- It's documented in files
- Memory contains the context
## Decision Tree
```
Need info?
↓
Files have it? → YES → Use file info
↓ NO
Memory has it? → YES → Use memory context
↓ NO
Ask user
```
## Examples
### Example 1: How does consolidation work?
❌ **Wrong**: "I don't know, let me ask the user"
✅ **Right**:
1. Read `src/mcp_memory_service/consolidation/compression.py`
2. Search memory: `"consolidation system design"`
3. Only ask if still unclear (rare)
### Example 2: Why did we choose ONNX over Groq?
❌ **Wrong**: Read all quality scoring code
✅ **Right**:
1. Check if code comments explain (quick scan)
2. **Search memory**: `"quality scoring design decision ONNX Groq"`
3. Ask user if no memory found
### Example 3: Should I use approach A or B?
✅ **Right**:
1. Check if similar pattern exists in codebase
2. Search memory for architectural decisions
3. **Ask user** (design choice, user decides)
### Example 4: What's the correct API call format?
❌ **Wrong**: Ask user
✅ **Right**:
1. Check code examples in `src/mcp_memory_service/web/api/`
2. Search memory: `"api reference quick-reference"`
3. Only ask if genuinely unclear
## Memory Search Best Practices
- **Be specific**: `"consolidation cluster deduplication"` not just `"consolidation"`
- **Use project tag**: All relevant memories tagged with `mcp-memory-service`
- **Search by tags**: `retrieve_by_tags(["architecture", "decision"])`
- **Timeframe matters**: Recent decisions may override old ones (check created_at)
- **Check quality**: High-quality memories (score ≥0.7) are more reliable
## When Memory Conflicts with Files
**Files always win.** If memory says X but code does Y:
- Code is current truth
- Memory is historical context
- Note the discrepancy (code evolved since memory was stored)
```
--------------------------------------------------------------------------------
/src/mcp_memory_service/__init__.py:
--------------------------------------------------------------------------------
```python
# Copyright 2024 Heinrich Krupp
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""MCP Memory Service initialization."""
# CRITICAL: Set offline mode BEFORE any other imports to prevent model downloads
import os
import platform
# Force offline mode for HuggingFace models - this MUST be done before any ML library imports
def setup_offline_mode():
"""Setup offline mode environment variables to prevent model downloads.
Offline mode is only enabled if:
1. User explicitly sets MCP_MEMORY_OFFLINE=1, OR
2. User has already set HF_HUB_OFFLINE or TRANSFORMERS_OFFLINE
This allows first-time installations to download models when needed.
"""
# Configure cache paths first (always needed)
username = os.environ.get('USERNAME', os.environ.get('USER', ''))
if platform.system() == "Windows" and username:
default_hf_home = f"C:\\Users\\{username}\\.cache\\huggingface"
default_transformers_cache = f"C:\\Users\\{username}\\.cache\\huggingface\\transformers"
default_sentence_transformers_home = f"C:\\Users\\{username}\\.cache\\torch\\sentence_transformers"
else:
default_hf_home = os.path.expanduser("~/.cache/huggingface")
default_transformers_cache = os.path.expanduser("~/.cache/huggingface/transformers")
default_sentence_transformers_home = os.path.expanduser("~/.cache/torch/sentence_transformers")
# Set cache paths if not already set
if 'HF_HOME' not in os.environ:
os.environ['HF_HOME'] = default_hf_home
if 'TRANSFORMERS_CACHE' not in os.environ:
os.environ['TRANSFORMERS_CACHE'] = default_transformers_cache
if 'SENTENCE_TRANSFORMERS_HOME' not in os.environ:
os.environ['SENTENCE_TRANSFORMERS_HOME'] = default_sentence_transformers_home
# Only set offline mode if explicitly requested
# This allows first-time installations to download models when network is available
offline_requested = os.environ.get('MCP_MEMORY_OFFLINE', '').lower() in ('1', 'true', 'yes')
already_offline = (
os.environ.get('HF_HUB_OFFLINE', '').lower() in ('1', 'true', 'yes') or
os.environ.get('TRANSFORMERS_OFFLINE', '').lower() in ('1', 'true', 'yes')
)
if offline_requested or already_offline:
os.environ['HF_HUB_OFFLINE'] = '1'
os.environ['TRANSFORMERS_OFFLINE'] = '1'
# Setup offline mode (conditionally) when this module is imported
setup_offline_mode()
# Import version from separate file to avoid loading heavy dependencies
from ._version import __version__
from .models import Memory, MemoryQueryResult
from .storage import MemoryStorage
from .utils import generate_content_hash
# Conditional imports
__all__ = [
'Memory',
'MemoryQueryResult',
'MemoryStorage',
'generate_content_hash'
]
# Import storage backends conditionally
try:
from .storage import SqliteVecMemoryStorage
__all__.append('SqliteVecMemoryStorage')
except ImportError:
SqliteVecMemoryStorage = None
```
--------------------------------------------------------------------------------
/docs/glama-deployment.md:
--------------------------------------------------------------------------------
```markdown
# Glama Deployment Guide
This guide provides instructions for deploying the MCP Memory Service on the Glama platform.
## Overview
The MCP Memory Service is now available on Glama at: https://glama.ai/mcp/servers/bzvl3lz34o
Glama is a directory for MCP servers that provides easy discovery and deployment options for users.
## Docker Configuration for Glama
### Primary Dockerfile
The repository includes an optimized Dockerfile specifically for Glama deployment:
- `Dockerfile` - Main production Dockerfile
- `Dockerfile.glama` - Glama-optimized version with enhanced labels and health checks
### Key Features
1. **Multi-platform Support**: Works on x86_64 and ARM64 architectures
2. **Health Checks**: Built-in health monitoring for container status
3. **Data Persistence**: Proper volume configuration for ChromaDB and backups
4. **Environment Configuration**: Pre-configured for optimal performance
5. **Security**: Minimal attack surface with slim Python base image
### Quick Start from Glama
Users can deploy the service using:
```bash
# Using the Glama-provided configuration
docker run -d -p 8000:8000 \
-v $(pwd)/data/chroma_db:/app/chroma_db \
-v $(pwd)/data/backups:/app/backups \
doobidoo/mcp-memory-service:latest
```
### Environment Variables
The following environment variables are pre-configured:
| Variable | Value | Purpose |
|----------|-------|---------|
| `MCP_MEMORY_CHROMA_PATH` | `/app/chroma_db` | ChromaDB storage location |
| `MCP_MEMORY_BACKUPS_PATH` | `/app/backups` | Backup storage location |
| `DOCKER_CONTAINER` | `1` | Indicates Docker environment |
| `CHROMA_TELEMETRY_IMPL` | `none` | Disables ChromaDB telemetry |
| `PYTORCH_ENABLE_MPS_FALLBACK` | `1` | Enables MPS fallback for Apple Silicon |
### Standalone Mode
For deployment without an active MCP client, use:
```bash
docker run -d -p 8000:8000 \
-e MCP_STANDALONE_MODE=1 \
-v $(pwd)/data/chroma_db:/app/chroma_db \
-v $(pwd)/data/backups:/app/backups \
doobidoo/mcp-memory-service:latest
```
## Glama Platform Integration
### Server Verification
The Dockerfile passes all Glama server checks:
- ✅ Valid Dockerfile syntax
- ✅ Proper base image
- ✅ Security best practices
- ✅ Health check implementation
- ✅ Volume configuration
- ✅ Port exposure
### User Experience
Glama users benefit from:
1. **One-click deployment** from the Glama interface
2. **Pre-configured settings** for immediate use
3. **Documentation integration** with setup instructions
4. **Community feedback** and ratings
5. **Version tracking** and update notifications
### Monitoring and Health
The Docker image includes health checks that verify:
- Python environment is working
- MCP Memory Service can be imported
- Dependencies are properly loaded
## Maintenance
### Updates
The Glama listing is automatically updated when:
1. New versions are tagged in the GitHub repository
2. Docker images are published to Docker Hub
3. Documentation is updated
### Support
For Glama-specific issues:
1. Check the Glama platform documentation
2. Verify Docker configuration
3. Review container logs for errors
4. Test with standalone mode for debugging
## Contributing
To improve the Glama integration:
1. Test the deployment on different platforms
2. Provide feedback on the installation experience
3. Suggest improvements to the Docker configuration
4. Report any platform-specific issues
The goal is to make the MCP Memory Service as accessible as possible to the 60k+ monthly Glama users.
```
--------------------------------------------------------------------------------
/scripts/run/memory_wrapper_cleanup.ps1:
--------------------------------------------------------------------------------
```
# MCP Memory Service Wrapper with Orphan Cleanup
#
# Cleans up orphaned MCP memory processes before starting the server.
# Orphaned processes cause SQLite "database locked" errors.
#
# Usage in MCP config:
# {
# "memory": {
# "command": "powershell",
# "args": ["-ExecutionPolicy", "Bypass", "-File", "C:\\path\\to\\scripts\\run\\memory_wrapper_cleanup.ps1"],
# "env": { ... }
# }
# }
$ErrorActionPreference = "Stop"
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
$ProjectDir = Split-Path -Parent (Split-Path -Parent $ScriptDir)
function Write-Log {
param([string]$Message)
Write-Host "[mcp-memory-wrapper] $Message" -ForegroundColor Cyan
}
function Get-OrphanedProcesses {
<#
.SYNOPSIS
Find MCP memory processes whose parent no longer exists (orphaned).
#>
$orphans = @()
try {
# Get all Python processes running mcp-memory-service
$mcpProcesses = Get-WmiObject Win32_Process -Filter "CommandLine LIKE '%mcp-memory-service%'" -ErrorAction SilentlyContinue
foreach ($proc in $mcpProcesses) {
# Skip our own process
if ($proc.ProcessId -eq $PID) {
continue
}
# Check if parent process exists
$parentExists = Get-Process -Id $proc.ParentProcessId -ErrorAction SilentlyContinue
if (-not $parentExists) {
$orphans += $proc.ProcessId
}
}
}
catch {
Write-Log "Warning: Error checking for orphans: $_"
}
return $orphans
}
function Remove-OrphanedProcesses {
<#
.SYNOPSIS
Kill orphaned MCP memory processes.
#>
$orphans = Get-OrphanedProcesses
if ($orphans.Count -gt 0) {
Write-Log "Found $($orphans.Count) orphaned process(es): $($orphans -join ', ')"
foreach ($pid in $orphans) {
try {
Stop-Process -Id $pid -Force -ErrorAction SilentlyContinue
Write-Log "Terminated orphaned process: $pid"
}
catch {
Write-Log "Failed to terminate process $pid : $_"
}
}
}
else {
Write-Log "No orphaned processes found"
}
}
function Find-Uv {
<#
.SYNOPSIS
Find the uv executable.
#>
# Check if uv is in PATH
$uvPath = Get-Command uv -ErrorAction SilentlyContinue
if ($uvPath) {
return $uvPath.Path
}
# Check common locations
$commonPaths = @(
"$env:USERPROFILE\.local\bin\uv.exe",
"$env:USERPROFILE\.cargo\bin\uv.exe",
"$env:LOCALAPPDATA\Programs\uv\uv.exe"
)
foreach ($path in $commonPaths) {
if (Test-Path $path) {
return $path
}
}
Write-Log "ERROR: uv not found. Install with: irm https://astral.sh/uv/install.ps1 | iex"
exit 1
}
function Start-MemoryServer {
<#
.SYNOPSIS
Start the MCP memory server.
#>
Set-Location $ProjectDir
$uv = Find-Uv
Write-Log "Starting server with: $uv run memory"
# Start the server (this replaces our process)
& $uv run memory $args
exit $LASTEXITCODE
}
# Main execution
try {
Write-Log "Starting (Windows $([System.Environment]::OSVersion.Version))"
# Step 1: Cleanup orphans
Remove-OrphanedProcesses
# Step 2: Start server
Start-MemoryServer
}
catch {
Write-Log "Fatal error: $_"
exit 1
}
```
--------------------------------------------------------------------------------
/scripts/testing/test_memory_simple.py:
--------------------------------------------------------------------------------
```python
#!/usr/bin/env python3
# Copyright 2024 Heinrich Krupp
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Simple test for memory CRUD operations."""
import requests
import json
import time
BASE_URL = "http://localhost:8000"
def test_memory_crud():
"""Test the complete CRUD workflow for memories."""
print("Testing Memory CRUD Operations")
print("=" * 40)
# Test 1: Health check
print("\n[1] Health check...")
try:
resp = requests.get(f"{BASE_URL}/api/health", timeout=5)
if resp.status_code == 200:
print("[PASS] Server is healthy")
else:
print(f"[FAIL] Health check failed: {resp.status_code}")
return
except Exception as e:
print(f"[FAIL] Cannot connect: {e}")
return
# Test 2: Store memory
print("\n[2] Storing memory...")
test_memory = {
"content": "Test memory for API verification",
"tags": ["test", "api"],
"memory_type": "test",
"metadata": {"timestamp": time.time()}
}
try:
resp = requests.post(
f"{BASE_URL}/api/memories",
json=test_memory,
headers={"Content-Type": "application/json"},
timeout=10
)
if resp.status_code == 200:
result = resp.json()
if result["success"]:
content_hash = result["content_hash"]
print(f"[PASS] Memory stored: {content_hash[:12]}...")
else:
print(f"[FAIL] Storage failed: {result['message']}")
return
else:
print(f"[FAIL] Storage failed: {resp.status_code}")
print(f"Error: {resp.text}")
return
except Exception as e:
print(f"[FAIL] Storage error: {e}")
return
# Test 3: List memories
print("\n[3] Listing memories...")
try:
resp = requests.get(f"{BASE_URL}/api/memories?page=1&page_size=5", timeout=10)
if resp.status_code == 200:
result = resp.json()
print(f"[PASS] Found {len(result['memories'])} memories")
print(f"Total: {result['total']}")
else:
print(f"[FAIL] Listing failed: {resp.status_code}")
except Exception as e:
print(f"[FAIL] Listing error: {e}")
# Test 4: Delete memory
print("\n[4] Deleting memory...")
try:
resp = requests.delete(f"{BASE_URL}/api/memories/{content_hash}", timeout=10)
if resp.status_code == 200:
result = resp.json()
if result["success"]:
print("[PASS] Memory deleted")
else:
print(f"[FAIL] Deletion failed: {result['message']}")
else:
print(f"[FAIL] Deletion failed: {resp.status_code}")
except Exception as e:
print(f"[FAIL] Deletion error: {e}")
print("\n" + "=" * 40)
print("CRUD testing completed!")
if __name__ == "__main__":
test_memory_crud()
```
--------------------------------------------------------------------------------
/src/mcp_memory_service/web/oauth/discovery.py:
--------------------------------------------------------------------------------
```python
# Copyright 2024 Heinrich Krupp
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
OAuth 2.1 Discovery endpoints for MCP Memory Service.
Implements .well-known endpoints required for OAuth 2.1 Dynamic Client Registration.
"""
import logging
from fastapi import APIRouter
from ...config import OAUTH_ISSUER, get_jwt_algorithm
from .models import OAuthServerMetadata
logger = logging.getLogger(__name__)
router = APIRouter()
@router.get("/.well-known/oauth-authorization-server/mcp")
async def oauth_authorization_server_metadata() -> OAuthServerMetadata:
"""
OAuth 2.1 Authorization Server Metadata endpoint.
Returns metadata about the OAuth 2.1 authorization server as specified
in RFC 8414. This endpoint is required for OAuth 2.1 Dynamic Client Registration.
"""
logger.info("OAuth authorization server metadata requested")
# Use OAUTH_ISSUER consistently for both issuer field and endpoint URLs
# This ensures URL consistency across discovery and JWT token validation
algorithm = get_jwt_algorithm()
metadata = OAuthServerMetadata(
issuer=OAUTH_ISSUER,
authorization_endpoint=f"{OAUTH_ISSUER}/oauth/authorize",
token_endpoint=f"{OAUTH_ISSUER}/oauth/token",
registration_endpoint=f"{OAUTH_ISSUER}/oauth/register",
grant_types_supported=["authorization_code", "client_credentials"],
response_types_supported=["code"],
token_endpoint_auth_methods_supported=["client_secret_basic", "client_secret_post"],
scopes_supported=["read", "write", "admin"],
id_token_signing_alg_values_supported=[algorithm]
)
logger.debug(f"Returning OAuth metadata: issuer={metadata.issuer}")
return metadata
@router.get("/.well-known/openid-configuration/mcp")
async def openid_configuration() -> OAuthServerMetadata:
"""
OpenID Connect Discovery endpoint.
Some OAuth 2.1 clients may also check this endpoint for compatibility.
For now, we return the same metadata as the OAuth authorization server.
"""
logger.info("OpenID Connect configuration requested")
# Return the same metadata as OAuth authorization server for compatibility
return await oauth_authorization_server_metadata()
@router.get("/.well-known/oauth-authorization-server")
async def oauth_authorization_server_metadata_generic() -> OAuthServerMetadata:
"""
Generic OAuth 2.1 Authorization Server Metadata endpoint.
Fallback endpoint for clients that don't append the /mcp suffix.
"""
logger.info("Generic OAuth authorization server metadata requested")
return await oauth_authorization_server_metadata()
@router.get("/.well-known/openid-configuration")
async def openid_configuration_generic() -> OAuthServerMetadata:
"""
Generic OpenID Connect Discovery endpoint.
Fallback endpoint for clients that don't append the /mcp suffix.
"""
logger.info("Generic OpenID Connect configuration requested")
return await oauth_authorization_server_metadata()
```
--------------------------------------------------------------------------------
/tests/unit/test_uv_no_pip_installer_fallback.py:
--------------------------------------------------------------------------------
```python
import importlib.util
import sys
from pathlib import Path
def _load_install_py_module(monkeypatch, base_dir: Path):
repo_root = Path(__file__).resolve().parents[2]
# Avoid touching user-global app support directories during import.
monkeypatch.setenv("MCP_MEMORY_BASE_DIR", str(base_dir))
install_py = repo_root / "install.py"
spec = importlib.util.spec_from_file_location("mcp_memory_service_install_py", install_py)
assert spec and spec.loader
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
return module
def test_install_py_uses_pip_when_available(monkeypatch, tmp_path):
install_module = _load_install_py_module(monkeypatch, tmp_path)
recorded = {}
def fake_check_call(cmd, **kwargs):
recorded["cmd"] = cmd
recorded["kwargs"] = kwargs
return 0
monkeypatch.setattr(install_module, "_pip_available", lambda: True)
monkeypatch.setattr(install_module, "subprocess", install_module.subprocess)
monkeypatch.setattr(install_module.subprocess, "check_call", fake_check_call)
install_module._install_python_packages(["sqlite-vec"], extra_args=["--no-deps"], silent=True)
assert recorded["cmd"][:4] == [sys.executable, "-m", "pip", "install"]
assert "--no-deps" in recorded["cmd"]
assert "sqlite-vec" in recorded["cmd"]
assert "stdout" in recorded["kwargs"]
assert "stderr" in recorded["kwargs"]
def test_install_py_uses_uv_when_pip_missing(monkeypatch, tmp_path):
install_module = _load_install_py_module(monkeypatch, tmp_path)
recorded = {}
def fake_check_call(cmd, **kwargs):
recorded["cmd"] = cmd
recorded["kwargs"] = kwargs
return 0
monkeypatch.setattr(install_module, "_pip_available", lambda: False)
monkeypatch.setattr(install_module, "_uv_executable", lambda: "/opt/homebrew/bin/uv")
monkeypatch.setattr(install_module.subprocess, "check_call", fake_check_call)
install_module._install_python_packages(["sqlite-vec"])
assert recorded["cmd"][:3] == ["/opt/homebrew/bin/uv", "pip", "install"]
assert "--python" in recorded["cmd"]
assert sys.executable in recorded["cmd"]
assert "sqlite-vec" in recorded["cmd"]
def test_scripts_installer_uses_uv_when_pip_module_missing(monkeypatch):
from scripts.installation import install as scripts_install
recorded = {}
def fake_run_command_safe(cmd, **kwargs):
recorded["cmd"] = cmd
recorded["kwargs"] = kwargs
return True, None
monkeypatch.setattr(scripts_install.importlib.util, "find_spec", lambda name: None)
monkeypatch.setattr(scripts_install.shutil, "which", lambda name: "/opt/homebrew/bin/uv")
monkeypatch.setattr(scripts_install, "run_command_safe", fake_run_command_safe)
ok = scripts_install.install_package_safe("sqlite-vec", fallback_in_venv=False)
assert ok is True
assert recorded["cmd"][:3] == ["/opt/homebrew/bin/uv", "pip", "install"]
assert "--python" in recorded["cmd"]
assert sys.executable in recorded["cmd"]
assert "sqlite-vec" in recorded["cmd"]
def test_scripts_installer_returns_false_when_no_pip_and_no_uv(monkeypatch):
from scripts.installation import install as scripts_install
monkeypatch.setattr(scripts_install.importlib.util, "find_spec", lambda name: None)
monkeypatch.setattr(scripts_install.shutil, "which", lambda name: None)
ok = scripts_install.install_package_safe("sqlite-vec", fallback_in_venv=False)
assert ok is False
```
--------------------------------------------------------------------------------
/.claude/directives/code-quality-workflow.md:
--------------------------------------------------------------------------------
```markdown
# Code Quality Workflow - Multi-Layer Strategy
## Three-Layer Quality Assurance
The QA workflow uses three complementary layers for comprehensive code quality assurance:
### Layer 1: Pre-commit (Fast - <5s)
- Groq/Gemini LLM complexity checks
- Security scanning (SQL injection, XSS, command injection)
- Dev environment validation
- **Blocking**: Complexity >8, any security issues
### Layer 2: PR Quality Gate (Moderate - 10-60s)
- Standard checks: complexity, security, test coverage, breaking changes
- Comprehensive checks (`--with-pyscn`): + duplication, dead code, architecture
- **Blocking**: Security issues, health score <50
### Layer 3: Periodic Review (Weekly)
- pyscn codebase-wide analysis
- Trend tracking and regression detection
- Refactoring sprint planning
## pyscn Integration
[pyscn](https://github.com/ludo-technologies/pyscn) provides comprehensive static analysis:
**Capabilities:**
- Cyclomatic complexity scoring
- Dead code detection
- Clone detection (duplication)
- Coupling metrics (CBO)
- Dependency graph analysis
- Architecture violation detection
**Usage:**
```bash
# PR creation (automated)
bash scripts/pr/quality_gate.sh 123 --with-pyscn
# Local pre-PR check
pyscn analyze .
open .pyscn/reports/analyze_*.html
# Track metrics over time
bash scripts/quality/track_pyscn_metrics.sh
# Weekly review
bash scripts/quality/weekly_quality_review.sh
```
## Health Score Thresholds
| Score | Status | Action Required |
|-------|--------|----------------|
| **<50** | 🔴 **Release Blocker** | Cannot merge - immediate refactoring required |
| **50-69** | 🟡 **Action Required** | Plan refactoring sprint within 2 weeks |
| **70-84** | ✅ **Good** | Monitor trends, continue development |
| **85+** | 🎯 **Excellent** | Maintain current standards |
## Quality Standards
**Release Blockers** (Health Score <50):
- ❌ Cannot merge to main
- ❌ Cannot create release
- 🔧 Required: Immediate refactoring
**Action Required** (Health Score 50-69):
- ⚠️ Plan refactoring sprint within 2 weeks
- 📊 Track on project board
- 🎯 Focus on top 5 complexity offenders
**Acceptable** (Health Score ≥70):
- ✅ Continue normal development
- 📈 Monitor trends monthly
- 🎯 Address new issues proactively
## Tool Complementarity
| Tool | Speed | Scope | Use Case | Blocking |
|------|-------|-------|----------|----------|
| **Groq/Gemini (pre-commit)** | <5s | Changed files | Every commit | Yes (complexity >8) |
| **quality_gate.sh** | 10-30s | PR files | PR creation | Yes (security) |
| **pyscn (PR)** | 30-60s | Full codebase | PR + periodic | Yes (health <50) |
| **code-quality-guard** | Manual | Targeted | Refactoring | No (advisory) |
## Integration Points
- **Pre-commit**: Fast LLM checks (Groq primary, Gemini fallback)
- **PR Quality Gate**: `--with-pyscn` flag for comprehensive analysis
- **Periodic**: Weekly pyscn analysis with trend tracking
## Pre-commit Hook Setup
```bash
# Recommended: Groq for fast, non-interactive checks
export GROQ_API_KEY="your-groq-api-key" # Primary (200-300ms, no OAuth)
# Falls back to Gemini CLI if Groq unavailable
# Skips checks gracefully if neither available
# Enable pre-commit hook
ln -s ../../scripts/hooks/pre-commit .git/hooks/pre-commit
```
**LLM Priority:**
1. **Groq API** (Primary) - Fast (200-300ms), simple API key auth
2. **Gemini CLI** (Fallback) - Slower (2-3s), OAuth browser flow
3. **Skip checks** - If neither available, commit proceeds
See [`.claude/agents/code-quality-guard.md`](../.claude/agents/code-quality-guard.md) for detailed workflows.
```
--------------------------------------------------------------------------------
/docs/mastery/api-reference.md:
--------------------------------------------------------------------------------
```markdown
# MCP Memory Service — API Reference
This document catalogs available APIs exposed via the MCP servers and summarizes request and response patterns.
## MCP (FastMCP HTTP) Tools
Defined in `src/mcp_memory_service/mcp_server.py` using `@mcp.tool()`:
- `store_memory(content, tags=None, memory_type="note", metadata=None, client_hostname=None)`
- Stores a new memory; tags and metadata optional. If `INCLUDE_HOSTNAME=true`, a `source:<hostname>` tag and `hostname` metadata are added.
- Response: `{ success: bool, message: str, content_hash: str }`.
- `retrieve_memory(query, n_results=5, min_similarity=0.0)`
- Semantic search by query; returns up to `n_results` matching memories.
- Response: `{ memories: [{ content, content_hash, tags, memory_type, created_at, similarity_score }...], query, total_results }`.
- `search_by_tag(tags, match_all=False)`
- Search by a tag or list of tags. `match_all=true` requires all tags; otherwise any.
- Response: `{ memories: [{ content, content_hash, tags, memory_type, created_at }...], search_tags: [...], match_all, total_results }`.
- `delete_memory(content_hash)`
- Deletes a memory by its content hash.
- Response: `{ success: bool, message: str, content_hash }`.
- `check_database_health()`
- Health and status of the configured backend.
- Response: `{ status: "healthy"|"error", backend, statistics: { total_memories, total_tags, storage_size, last_backup }, timestamp? }`.
Transport: `mcp.run("streamable-http")`, default host `0.0.0.0`, default port `8000` or `MCP_SERVER_PORT`/`MCP_SERVER_HOST`.
## MCP (stdio) Server Tools and Prompts
Defined in `src/mcp_memory_service/server.py` using `mcp.server.Server`. Exposes a broader set of tools/prompts beyond the core FastMCP tools above.
Highlights:
- Core memory ops: store, retrieve/search, search_by_tag(s), delete, delete_by_tag, cleanup_duplicates, update_memory_metadata, time-based recall.
- Analysis/export: knowledge_analysis, knowledge_export (supports `format: json|markdown|text`, optional filters).
- Maintenance: memory_cleanup (duplicate detection heuristics), health/stats, tag listing.
- Consolidation (optional): association, clustering, compression, forgetting tasks and schedulers when enabled.
Note: The stdio server dynamically picks storage mode for multi-client scenarios (direct SQLite-vec with WAL vs. HTTP coordination), suppresses stdout for Claude Desktop, and prints richer diagnostics for LM Studio.
## HTTP Interface
- For FastMCP, HTTP transport is used to carry MCP protocol; endpoints are handled by the FastMCP layer and not intended as a REST API surface.
- A dedicated HTTP API and dashboard exist under `src/mcp_memory_service/web/` in some distributions. In this repo version, coordination HTTP is internal and the recommended external interface is MCP.
## Error Model and Logging
- MCP tool errors are surfaced as `{ success: false, message: <details> }` or include `error` fields.
- Logging routes WARNING+ to stderr (Claude Desktop strict mode), info/debug to stdout only for LM Studio; set `LOG_LEVEL` for verbosity.
## Examples
Store memory:
```
tool: store_memory
args: { "content": "Refactored auth flow to use OAuth 2.1", "tags": ["auth", "refactor"], "memory_type": "note" }
```
Retrieve by query:
```
tool: retrieve_memory
args: { "query": "OAuth refactor", "n_results": 5 }
```
Search by tags:
```
tool: search_by_tag
args: { "tags": ["auth", "refactor"], "match_all": true }
```
Delete by hash:
```
tool: delete_memory
args: { "content_hash": "<hash>" }
```
```
--------------------------------------------------------------------------------
/scripts/pr/detect_breaking_changes.sh:
--------------------------------------------------------------------------------
```bash
#!/bin/bash
# scripts/pr/detect_breaking_changes.sh - Analyze API changes for breaking changes
#
# Usage: bash scripts/pr/detect_breaking_changes.sh <BASE_BRANCH> [HEAD_BRANCH]
# Example: bash scripts/pr/detect_breaking_changes.sh main feature/new-api
set -e
BASE_BRANCH=${1:-main}
HEAD_BRANCH=${2:-$(git branch --show-current)}
if [ -z "$BASE_BRANCH" ]; then
echo "Usage: $0 <BASE_BRANCH> [HEAD_BRANCH]"
echo "Example: $0 main feature/new-api"
exit 1
fi
if ! command -v gemini &> /dev/null; then
echo "Error: Gemini CLI is not installed"
exit 1
fi
echo "=== Breaking Change Detection ==="
echo "Base branch: $BASE_BRANCH"
echo "Head branch: $HEAD_BRANCH"
echo ""
# Get API-related file changes
echo "Analyzing API changes..."
api_changes=$(git diff $BASE_BRANCH...$HEAD_BRANCH -- \
src/mcp_memory_service/tools.py \
src/mcp_memory_service/web/api/ \
src/mcp_memory_service/storage/base.py \
2>/dev/null || echo "")
if [ -z "$api_changes" ]; then
echo "✅ No API changes detected"
echo ""
echo "Checked paths:"
echo "- src/mcp_memory_service/tools.py (MCP tools)"
echo "- src/mcp_memory_service/web/api/ (Web API endpoints)"
echo "- src/mcp_memory_service/storage/base.py (Storage interface)"
exit 0
fi
echo "API changes detected. Analyzing for breaking changes..."
echo ""
# Check diff size and warn if large
diff_lines=$(echo "$api_changes" | wc -l)
if [ $diff_lines -gt 200 ]; then
echo "⚠️ Warning: Large diff ($diff_lines lines) - analysis may miss changes beyond model context window"
echo " Consider reviewing the full diff manually for breaking changes"
fi
# Analyze with Gemini (full diff, not truncated)
result=$(gemini "Analyze these API changes for BREAKING CHANGES ONLY.
A breaking change is:
1. **Removed** function, method, class, or HTTP endpoint
2. **Changed function signature**: parameters removed, reordered, or made required
3. **Changed return type**: incompatible return value structure
4. **Renamed public API**: function, class, endpoint renamed without alias
5. **Changed HTTP endpoint**: path or method changed
6. **Removed configuration option**: environment variable or config field removed
NON-BREAKING changes (ignore these):
- Added new functions/endpoints (backward compatible)
- Added optional parameters with defaults
- Improved documentation
- Internal implementation changes
- Refactoring that preserves public interface
For each breaking change, provide:
- Severity: CRITICAL (data loss/security) / HIGH (blocks upgrade) / MEDIUM (migration effort)
- Type: Removed / Signature Changed / Renamed / etc.
- Location: File and function/endpoint name
- Impact: What breaks for users
- Migration: How users should adapt
API Changes:
\`\`\`diff
$api_changes
\`\`\`
Output format:
If breaking changes found:
## BREAKING CHANGES DETECTED
### [SEVERITY] Type: Location
**Impact:** <description>
**Migration:** <instructions>
If no breaking changes:
No breaking changes detected.")
echo "$result"
echo ""
# Check severity
if echo "$result" | grep -qi "CRITICAL"; then
echo "🔴 CRITICAL breaking changes detected!"
exit 3
elif echo "$result" | grep -qi "HIGH"; then
echo "🟠 HIGH severity breaking changes detected!"
exit 2
elif echo "$result" | grep -qi "MEDIUM"; then
echo "🟡 MEDIUM severity breaking changes detected"
exit 1
elif echo "$result" | grep -qi "breaking"; then
echo "⚠️ Breaking changes detected (unspecified severity)"
exit 1
else
echo "✅ No breaking changes detected"
exit 0
fi
```
--------------------------------------------------------------------------------
/claude_commands/memory-recall.md:
--------------------------------------------------------------------------------
```markdown
# Recall Memories by Time and Context
I'll help you retrieve memories from your MCP Memory Service using natural language time expressions and contextual queries. This command excels at finding past conversations, decisions, and notes based on when they occurred.
## What I'll do:
1. **Parse Time Expressions**: I'll interpret natural language time queries like:
- "yesterday", "last week", "two months ago"
- "last Tuesday", "this morning", "last summer"
- "before the database migration", "since we started using SQLite"
2. **Context-Aware Search**: I'll consider the current project context to find relevant memories related to your current work.
3. **Smart Filtering**: I'll automatically filter results to show the most relevant memories first, considering:
- Temporal relevance to your query
- Project and directory context matching
- Semantic similarity to current work
4. **Present Results**: I'll format the retrieved memories with clear context about when they were created and why they're relevant.
## Usage Examples:
```bash
claude /memory-recall "what did we decide about the database last week?"
claude /memory-recall "yesterday's architectural decisions"
claude /memory-recall "memories from when we were working on the mDNS feature"
claude /memory-recall --project "mcp-memory-service" "last month's progress"
```
## Implementation:
I'll connect to your MCP Memory Service at `https://memory.local:8443/` and use its API endpoints. The recall process involves:
1. **Query Processing**: Parse the natural language time expression and extract context clues
2. **Memory Retrieval**: Use the appropriate API endpoints:
- `POST /api/search/by-time` - Natural language time-based queries
- `POST /api/search` - Semantic search for context-based recall
- `GET /api/memories` - List memories with pagination and filtering
- `GET /api/memories/{hash}` - Retrieve specific memory by hash
3. **Context Matching**: Filter results based on current project and directory context
4. **Relevance Scoring**: Use similarity scores from the API responses
5. **Result Presentation**: Format memories with timestamps, tags, and relevance context
All requests use curl with `-k` flag for HTTPS and proper JSON formatting.
For each recalled memory, I'll show:
- **Content**: The actual memory content
- **Created**: When the memory was stored
- **Tags**: Associated tags and categories
- **Context**: Project and session context when stored
- **Relevance**: Why this memory matches your query
## Time Expression Examples:
- **Relative**: "yesterday", "last week", "two days ago", "this month"
- **Seasonal**: "last summer", "this winter", "spring 2024"
**Note**: Some expressions like "last hour" may not be supported by the time parser. Standard expressions like "today", "yesterday", "last week" work reliably.
- **Event-based**: "before the refactor", "since we switched to SQLite", "during the testing phase"
- **Specific**: "January 15th", "last Tuesday morning", "end of last month"
## Arguments:
- `$ARGUMENTS` - The time-based query, with optional flags:
- `--limit N` - Maximum number of memories to retrieve (default: 10)
- `--project "name"` - Filter by specific project
- `--tags "tag1,tag2"` - Additional tag filtering
- `--type "note|decision|task"` - Filter by memory type
- `--include-context` - Show full session context for each memory
If no memories are found for the specified time period, I'll suggest broadening the search or checking if the MCP Memory Service contains data for that timeframe.
```
--------------------------------------------------------------------------------
/scripts/quality/debug_deberta_scoring.py:
--------------------------------------------------------------------------------
```python
#!/usr/bin/env python3
"""
Debug script to examine DeBERTa raw outputs and scoring behavior.
"""
import sys
import numpy as np
from pathlib import Path
# Add src to path
sys.path.insert(0, str(Path(__file__).parent.parent.parent / "src"))
from mcp_memory_service.quality.onnx_ranker import ONNXRankerModel
def analyze_scoring(model, text, label):
"""Analyze raw model outputs for debugging."""
print(f"\n{'='*80}")
print(f"Testing: {label}")
print(f"Text: {text[:100]}...")
print(f"{'='*80}")
# Get inputs
text_input = text[:512]
inputs = model._tokenizer(
text_input,
padding=True,
truncation=True,
max_length=512,
return_tensors="np"
)
ort_inputs = {
"input_ids": inputs["input_ids"].astype(np.int64),
"attention_mask": inputs["attention_mask"].astype(np.int64)
}
# Run inference
outputs = model._model.run(None, ort_inputs)
logits = outputs[0][0]
print(f"\nRaw logits: {logits}")
print(f"Logits shape: {logits.shape}")
# Apply softmax
exp_logits = np.exp(logits - np.max(logits))
probs = exp_logits / exp_logits.sum()
print(f"\nSoftmax probabilities:")
print(f" P(Low): {probs[0]:.6f}")
print(f" P(Medium): {probs[1]:.6f}")
print(f" P(High): {probs[2]:.6f}")
# Calculate score
class_values = np.array([0.0, 0.5, 1.0])
score = float(np.dot(probs, class_values))
print(f"\nWeighted score: {score:.6f}")
print(f" Formula: 0.0×{probs[0]:.4f} + 0.5×{probs[1]:.4f} + 1.0×{probs[2]:.4f}")
# Also get score via API
api_score = model.score_quality("", text)
print(f" API score: {api_score:.6f}")
return score, probs
def main():
print("Initializing NVIDIA DeBERTa model...")
model = ONNXRankerModel(model_name="nvidia-quality-classifier-deberta", device="cpu")
# Test cases from the unit tests
test_cases = [
(
"Implement caching layer for API responses with Redis backend. Use TTL of 1 hour for user data.",
"High quality - specific implementation"
),
(
"Fix bug in user authentication flow. Added proper session validation and error handling.",
"High quality - bug fix with details"
),
(
"Meeting notes from team sync. Discussed project timeline and resource allocation.",
"Medium quality - general notes"
),
(
"Random thoughts about maybe doing something later.",
"Low quality - vague"
),
(
"TODO: check this",
"Low quality - minimal content"
),
(
"The implementation uses a sophisticated multi-tier architecture with semantic analysis, "
"pattern matching, and adaptive learning algorithms to optimize retrieval accuracy.",
"Excellent - from test"
),
(
"The code does some processing and returns a result.",
"Average - from test"
),
(
"stuff things maybe later TODO",
"Poor - from test"
)
]
results = []
for text, label in test_cases:
score, probs = analyze_scoring(model, text, label)
results.append((label, score, probs))
# Summary
print(f"\n{'='*80}")
print("SUMMARY")
print(f"{'='*80}")
for label, score, probs in results:
print(f"{label:40s} | Score: {score:.4f} | P(H/M/L): {probs[2]:.3f}/{probs[1]:.3f}/{probs[0]:.3f}")
if __name__ == "__main__":
main()
```
--------------------------------------------------------------------------------
/claude_commands/memory-store.md:
--------------------------------------------------------------------------------
```markdown
# Store Memory with Context
I'll help you store information in your MCP Memory Service with proper context and tagging. This command captures the current session context and stores it as a persistent memory that can be recalled later.
## What I'll do:
1. **Detect Current Context**: I'll analyze the current working directory, recent files, and conversation context to understand what we're working on.
2. **Capture Memory Content**: I'll take the provided information or current session summary and prepare it for storage.
3. **Add Smart Tags**: I'll automatically generate relevant tags based on:
- Machine hostname (source identifier)
- Current project directory name
- Programming languages detected
- File types and patterns
- Any explicit tags you provide
4. **Store with Metadata**: I'll include useful metadata like:
- Machine hostname for source tracking
- Timestamp and session context
- Project path and git repository info
- File associations and dependencies
## Usage Examples:
```bash
claude /memory-store "We decided to use SQLite-vec instead of ChromaDB for better performance"
claude /memory-store --tags "decision,architecture" "Database backend choice rationale"
claude /memory-store --type "note" "Remember to update the Docker configuration after the database change"
```
## Implementation:
I'll use a **hybrid remote-first approach** with local fallback for reliability:
### Primary: Remote API Storage
- **Try remote first**: `https://narrowbox.local:8443/api/memories`
- **Real-time sync**: Changes immediately available across all clients
- **Single source of truth**: Consolidated database on remote server
### Fallback: Local Staging
- **If remote fails**: Store locally in staging database for later sync
- **Offline capability**: Continue working when remote is unreachable
- **Auto-sync**: Changes pushed to remote when connectivity returns
### Smart Sync Workflow
```
1. Try remote API directly (fastest path)
2. If offline/failed: Stage locally + notify user
3. On reconnect: ./sync/memory_sync.sh automatically syncs
4. Conflict resolution: Remote wins, with user notification
```
The content will be stored with automatic context detection:
- **Machine Context**: Hostname automatically added as tag (e.g., "source:your-machine-name")
- **Project Context**: Current directory, git repository, recent commits
- **Session Context**: Current conversation topics and decisions
- **Technical Context**: Programming language, frameworks, and tools in use
- **Temporal Context**: Date, time, and relationship to recent activities
### Service Endpoints:
- **Primary API**: `https://narrowbox.local:8443/api/memories`
- **Sync Status**: Use `./sync/memory_sync.sh status` to check pending changes
- **Manual Sync**: Use `./sync/memory_sync.sh sync` for full synchronization
I'll use the correct curl syntax with `-k` flag for HTTPS, proper JSON payload formatting, and automatic client hostname detection using the `X-Client-Hostname` header.
## Arguments:
- `$ARGUMENTS` - The content to store as memory, or additional flags:
- `--tags "tag1,tag2"` - Explicit tags to add
- `--type "note|decision|task|reference"` - Memory type classification
- `--project "name"` - Override project name detection
- `--private` - Mark as private/sensitive content
I'll store the memory automatically without asking for confirmation. The memory will be saved immediately using proper JSON formatting with the curl command. You'll receive a brief confirmation showing the content hash and applied tags after successful storage.
```
--------------------------------------------------------------------------------
/scripts/maintenance/delete_orphaned_vectors_fixed.py:
--------------------------------------------------------------------------------
```python
#!/usr/bin/env python3
"""
Delete orphaned vectors from Cloudflare Vectorize using correct endpoint.
Uses /delete_by_ids (underscores, not hyphens) with proper JSON payload format.
"""
import asyncio
import os
import sys
from pathlib import Path
async def main():
# Set OAuth to false to avoid validation issues
os.environ['MCP_OAUTH_ENABLED'] = 'false'
# Import after setting environment
from mcp_memory_service.storage.cloudflare import CloudflareStorage
from mcp_memory_service.config import (
CLOUDFLARE_API_TOKEN, CLOUDFLARE_ACCOUNT_ID,
CLOUDFLARE_VECTORIZE_INDEX, CLOUDFLARE_D1_DATABASE_ID,
EMBEDDING_MODEL_NAME
)
# Read vector IDs from the completed hash file
hash_file = Path.home() / "cloudflare_d1_cleanup_completed.txt"
if not hash_file.exists():
print(f"❌ Error: Completed hash file not found: {hash_file}")
print(f" The D1 cleanup must be run first")
sys.exit(1)
print(f"📄 Reading vector IDs from: {hash_file}")
with open(hash_file) as f:
vector_ids = [line.strip() for line in f if line.strip()]
if not vector_ids:
print(f"✅ No vector IDs to delete (file is empty)")
sys.exit(0)
print(f"📋 Found {len(vector_ids)} orphaned vectors to delete")
print(f"🔗 Connecting to Cloudflare...\n")
# Initialize Cloudflare storage
cloudflare = CloudflareStorage(
api_token=CLOUDFLARE_API_TOKEN,
account_id=CLOUDFLARE_ACCOUNT_ID,
vectorize_index=CLOUDFLARE_VECTORIZE_INDEX,
d1_database_id=CLOUDFLARE_D1_DATABASE_ID,
embedding_model=EMBEDDING_MODEL_NAME
)
await cloudflare.initialize()
print(f"✅ Connected to Cloudflare")
print(f"🗑️ Deleting {len(vector_ids)} vectors using correct /delete_by_ids endpoint...\n")
deleted = 0
failed = []
# Batch delete in groups of 100 (API recommended batch size)
batch_size = 100
total_batches = (len(vector_ids) + batch_size - 1) // batch_size
for batch_num, i in enumerate(range(0, len(vector_ids), batch_size), 1):
batch = vector_ids[i:i+batch_size]
try:
# Use the public API method for better encapsulation
result = await cloudflare.delete_vectors_by_ids(batch)
if result.get("success"):
deleted += len(batch)
mutation_id = result.get("result", {}).get("mutationId", "N/A")
print(f"Batch {batch_num}/{total_batches}: ✓ Deleted {len(batch)} vectors (mutation: {mutation_id[:16]}...)")
else:
failed.extend(batch)
print(f"Batch {batch_num}/{total_batches}: ✗ Failed - {result.get('errors', 'Unknown error')}")
except Exception as e:
failed.extend(batch)
print(f"Batch {batch_num}/{total_batches}: ✗ Exception - {str(e)[:100]}")
# Final summary
print(f"\n{'='*60}")
print(f"📊 Vector Cleanup Summary")
print(f"{'='*60}")
print(f"✅ Successfully deleted: {deleted}/{len(vector_ids)}")
print(f"✗ Failed: {len(failed)}/{len(vector_ids)}")
print(f"{'='*60}\n")
if deleted > 0:
print(f"🎉 Vector cleanup complete!")
print(f"📋 {deleted} orphaned vectors removed from Vectorize")
print(f"⏱️ Note: Deletions are asynchronous and may take a few seconds to propagate\n")
if failed:
print(f"⚠️ {len(failed)} vectors failed to delete")
print(f" You may need to retry these manually\n")
return 0 if len(failed) == 0 else 1
if __name__ == "__main__":
sys.exit(asyncio.run(main()))
```
--------------------------------------------------------------------------------
/scripts/validation/verify_torch.py:
--------------------------------------------------------------------------------
```python
#!/usr/bin/env python3
# Copyright 2024 Heinrich Krupp
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
Verify PyTorch installation and functionality.
This script attempts to import PyTorch and run basic operations.
"""
import os
import sys
# Disable sitecustomize.py and other import hooks to prevent recursion issues
os.environ["PYTHONNOUSERSITE"] = "1" # Disable user site-packages
os.environ["PYTHONPATH"] = "" # Clear PYTHONPATH
def print_info(text):
"""Print formatted info text."""
print(f"[INFO] {text}")
def print_error(text):
"""Print formatted error text."""
print(f"[ERROR] {text}")
def print_success(text):
"""Print formatted success text."""
print(f"[SUCCESS] {text}")
def print_warning(text):
"""Print formatted warning text."""
print(f"[WARNING] {text}")
def verify_torch():
"""Verify PyTorch installation and functionality."""
print_info("Verifying PyTorch installation")
# Add site-packages to sys.path
site_packages = os.path.join(sys.prefix, 'Lib', 'site-packages')
if site_packages not in sys.path:
sys.path.insert(0, site_packages)
# Print sys.path for debugging
print_info("Python path:")
for path in sys.path:
print(f" - {path}")
# Try to import torch
try:
print_info("Attempting to import torch")
import torch
print_success(f"PyTorch is installed (version {torch.__version__})")
print_info(f"PyTorch location: {torch.__file__}")
# Check if CUDA is available
if torch.cuda.is_available():
print_success(f"CUDA is available (version {torch.version.cuda})")
print_info(f"GPU: {torch.cuda.get_device_name(0)}")
# Test a simple CUDA operation
try:
x = torch.rand(5, 3).cuda()
y = torch.rand(5, 3).cuda()
z = x + y
print_success("Basic CUDA tensor operations work correctly")
except Exception as e:
print_warning(f"CUDA tensor operations failed: {e}")
print_warning("Falling back to CPU mode")
else:
print_info("CUDA is not available, using CPU-only mode")
# Test a simple tensor operation
try:
x = torch.rand(5, 3)
y = torch.rand(5, 3)
z = x + y
print_success("Basic tensor operations work correctly")
except Exception as e:
print_error(f"Failed to perform basic tensor operations: {e}")
return False
return True
except ImportError as e:
print_error(f"PyTorch is not installed: {e}")
return False
except Exception as e:
print_error(f"Error checking PyTorch installation: {e}")
import traceback
traceback.print_exc()
return False
def main():
"""Main function."""
if verify_torch():
print_success("PyTorch verification completed successfully")
else:
print_error("PyTorch verification failed")
sys.exit(1)
if __name__ == "__main__":
main()
```
--------------------------------------------------------------------------------
/scripts/migration/migrate_to_sqlite_vec.py:
--------------------------------------------------------------------------------
```python
#!/usr/bin/env python3
"""
Simple migration script to help users migrate from ChromaDB to sqlite-vec.
This provides an easy way to switch to the lighter sqlite-vec backend.
"""
import os
import sys
import asyncio
from pathlib import Path
# Add scripts directory to path
sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'scripts'))
from migrate_storage import MigrationTool
async def main():
"""Simple migration from ChromaDB to sqlite-vec with sensible defaults."""
print("🔄 MCP Memory Service - Migrate to SQLite-vec")
print("=" * 50)
# Get default paths
home = Path.home()
if sys.platform == 'darwin': # macOS
base_dir = home / 'Library' / 'Application Support' / 'mcp-memory'
elif sys.platform == 'win32': # Windows
base_dir = Path(os.getenv('LOCALAPPDATA', '')) / 'mcp-memory'
else: # Linux
base_dir = home / '.local' / 'share' / 'mcp-memory'
chroma_path = base_dir / 'chroma_db'
sqlite_path = base_dir / 'sqlite_vec.db'
backup_path = base_dir / 'migration_backup.json'
print(f"📁 Source (ChromaDB): {chroma_path}")
print(f"📁 Target (SQLite-vec): {sqlite_path}")
print(f"💾 Backup: {backup_path}")
print()
# Check if source exists
if not chroma_path.exists():
print(f"❌ ChromaDB path not found: {chroma_path}")
print("💡 Make sure you have some memories stored first.")
return 1
# Check if target already exists
if sqlite_path.exists():
response = input(f"⚠️ SQLite-vec database already exists. Overwrite? (y/N): ")
if response.lower() != 'y':
print("❌ Migration cancelled")
return 1
# Confirm migration
print("🚀 Ready to migrate!")
print(" This will:")
print(" - Export all memories from ChromaDB")
print(" - Create a backup file")
print(" - Import memories to SQLite-vec")
print()
response = input("Continue? (Y/n): ")
if response.lower() == 'n':
print("❌ Migration cancelled")
return 1
# Perform migration
migration_tool = MigrationTool()
try:
success = await migration_tool.migrate(
from_backend='chroma',
to_backend='sqlite_vec',
source_path=str(chroma_path),
target_path=str(sqlite_path),
create_backup=True,
backup_path=str(backup_path)
)
if success:
print()
print("✅ Migration completed successfully!")
print()
print("📝 Next steps:")
print(" 1. Set environment variable: MCP_MEMORY_STORAGE_BACKEND=sqlite_vec")
print(" 2. Restart your MCP client (Claude Desktop)")
print(" 3. Test that your memories are accessible")
print()
print("🔧 Environment variable examples:")
print(" # Bash/Zsh:")
print(" export MCP_MEMORY_STORAGE_BACKEND=sqlite_vec")
print()
print(" # Windows Command Prompt:")
print(" set MCP_MEMORY_STORAGE_BACKEND=sqlite_vec")
print()
print(" # Windows PowerShell:")
print(" $env:MCP_MEMORY_STORAGE_BACKEND='sqlite_vec'")
print()
print(f"💾 Backup available at: {backup_path}")
return 0
else:
print("❌ Migration failed. Check logs for details.")
return 1
except Exception as e:
print(f"❌ Migration failed: {e}")
return 1
if __name__ == "__main__":
sys.exit(asyncio.run(main()))
```
--------------------------------------------------------------------------------
/docs/development/code-quality/phase-2a-index.md:
--------------------------------------------------------------------------------
```markdown
# Phase 2a Refactoring - Complete Documentation Index
**Status:** ✅ COMPLETE
**Date:** November 24, 2025
**Issue:** #246 - Code Quality Phase 2
---
## 📋 Documentation Files
### 1. PHASE_2A_COMPLETION_REPORT.md
**Comprehensive completion report with full metrics**
- Executive summary of achievements
- Detailed before/after analysis for each function
- Quality improvements across all dimensions
- Test suite status verification
- Lessons learned and recommendations
- 433 lines of detailed analysis
**Read this for:** Complete project overview and detailed metrics
### 2. REFACTORING_HANDLE_GET_PROMPT.md
**Function #6 refactoring specification - Latest completion**
- Function complexity reduction: 33 → 6 (82%)
- 5 specialized prompt handlers documented
- Design rationale and strategy
- Testing recommendations
- Code review checklist
- 194 lines of detailed specification
**Read this for:** In-depth look at the final refactoring completed
---
## 🔧 Code Changes
### Modified Files
**src/mcp_memory_service/server.py**
- Refactored `handle_get_prompt()` method
- Created 5 new helper methods:
- `_prompt_memory_review()`
- `_prompt_memory_analysis()`
- `_prompt_knowledge_export()`
- `_prompt_memory_cleanup()`
- `_prompt_learning_session()`
**src/mcp_memory_service/mcp_server.py**
- Fixed test collection error
- Added graceful FastMCP fallback
- `_DummyFastMCP` class for compatibility
---
## 📊 Summary Metrics
| Metric | Value |
|--------|-------|
| Functions Refactored | 6 of 27 (22%) |
| Average Complexity Reduction | 77% |
| Peak Complexity Reduction | 87% (62 → 8) |
| Tests Passing | 431 |
| Backward Compatibility | 100% |
| Health Score Improvement | 73/100 (target: 80/100) |
---
## ✅ Functions Completed
1. **install.py::main()** - 62 → 8 (87% ↓)
2. **sqlite_vec.py::initialize()** - Nesting 10 → 3 (70% ↓)
3. **config.py::__main__()** - 42 (validated extraction)
4. **oauth/authorization.py::token()** - 35 → 8 (77% ↓)
5. **install_package()** - 33 → 7 (78% ↓)
6. **handle_get_prompt()** - 33 → 6 (82% ↓) ⭐
---
## 🔗 Related Resources
- **GitHub Issue:** [#246 - Code Quality Phase 2](https://github.com/doobidoo/mcp-memory-service/issues/246)
- **Issue Comment:** [Phase 2a Progress Update](https://github.com/doobidoo/mcp-memory-service/issues/246#issuecomment-3572351946)
---
## 📈 Next Phases
### Phase 2a Continuation
- 21 remaining high-complexity functions
- Estimated: 2-3 release cycles
- Apply same successful patterns
### Phase 2b
- Code duplication consolidation
- 14 duplicate groups → reduce to <3%
- Estimated: 1-2 release cycles
### Phase 2c
- Architecture compliance violations
- 95.8% → 100% compliance
- Estimated: 1 release cycle
---
## 🎯 How to Use This Documentation
**For Code Review:**
1. Start with PHASE_2A_COMPLETION_REPORT.md for overview
2. Review REFACTORING_HANDLE_GET_PROMPT.md for detailed design
3. Check git commits for actual code changes
**For Continuation (Phase 2a):**
1. Review quality improvements in PHASE_2A_COMPLETION_REPORT.md
2. Follow same patterns: dispatcher + specialized handlers
3. Apply extract method for nesting reduction
4. Ensure backward compatibility maintained
**For Future Refactoring:**
- Use dispatcher pattern for multi-branch logic
- Extract methods for nesting depth >3
- Maintain single responsibility principle
- Always keep backward compatibility
---
## 🚀 Key Achievements
✅ 77% average complexity reduction
✅ 100% backward compatibility
✅ 431 tests passing
✅ Clear path for Phase 2b & 2c
✅ Comprehensive documentation
✅ Ready for review and merge
---
**Last Updated:** November 24, 2025
**Status:** COMPLETE AND VERIFIED
```
--------------------------------------------------------------------------------
/scripts/testing/run_complete_test.py:
--------------------------------------------------------------------------------
```python
#!/usr/bin/env python3
# Copyright 2024 Heinrich Krupp
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
Complete test suite for the HTTP/SSE + SQLite-vec implementation.
Runs all tests in sequence to validate the entire system.
"""
import subprocess
import sys
import time
import requests
from pathlib import Path
def check_server_health():
"""Check if the server is running and healthy."""
try:
response = requests.get("http://localhost:8000/api/health", timeout=5)
return response.status_code == 200
except:
return False
def run_test_script(script_name, description):
"""Run a test script and return success status."""
print(f"\n{'='*60}")
print(f"🧪 {description}")
print('='*60)
try:
# Run the test script
result = subprocess.run([
sys.executable,
str(Path(__file__).parent / script_name)
], capture_output=True, text=True, timeout=60)
if result.returncode == 0:
print("✅ Test PASSED")
if result.stdout:
print("Output:", result.stdout[-500:]) # Last 500 chars
return True
else:
print("❌ Test FAILED")
print("Error:", result.stderr)
return False
except subprocess.TimeoutExpired:
print("⏰ Test TIMED OUT")
return False
except Exception as e:
print(f"❌ Test ERROR: {e}")
return False
def main():
"""Run the complete test suite."""
print("🚀 MCP Memory Service - Complete Test Suite")
print("=" * 60)
# Check if server is running
if not check_server_health():
print("❌ Server is not running or not healthy!")
print("💡 Please start the server first:")
print(" python scripts/run_http_server.py")
return 1
print("✅ Server is healthy and ready for testing")
# Test suite configuration
tests = [
("test_memory_simple.py", "Memory CRUD Operations Test"),
("test_search_api.py", "Search API Functionality Test"),
("test_sse_events.py", "Real-time SSE Events Test"),
]
results = []
# Run each test
for script, description in tests:
success = run_test_script(script, description)
results.append((description, success))
if success:
print(f"✅ {description} - PASSED")
else:
print(f"❌ {description} - FAILED")
# Brief pause between tests
time.sleep(2)
# Summary
print(f"\n{'='*60}")
print("📊 TEST SUMMARY")
print('='*60)
passed = sum(1 for _, success in results if success)
total = len(results)
for description, success in results:
status = "✅ PASS" if success else "❌ FAIL"
print(f"{status} {description}")
print(f"\nResults: {passed}/{total} tests passed")
if passed == total:
print("\n🎉 ALL TESTS PASSED! System is working perfectly!")
return 0
else:
print(f"\n⚠️ {total - passed} tests failed. Check the logs above.")
return 1
if __name__ == "__main__":
sys.exit(main())
```
--------------------------------------------------------------------------------
/tests/integration/test_store_memory.py:
--------------------------------------------------------------------------------
```python
#!/usr/bin/env python3
"""
Test script to store a memory in the MCP Memory Service.
"""
import asyncio
import json
import os
import sys
# Import MCP client
try:
from mcp import ClientSession
from mcp.client.stdio import stdio_client, StdioServerParameters
except ImportError as e:
print(f"MCP client not found: {e}")
print("Install with: pip install mcp")
sys.exit(1)
async def store_memory():
"""Store a test memory."""
try:
# Configure MCP server connection
server_params = StdioServerParameters(
command="uv",
args=["run", "memory", "server"],
env=None
)
# Connect to memory service using stdio_client
async with stdio_client(server_params) as (read, write):
async with ClientSession(read, write) as session:
# Initialize the session
await session.initialize()
print("Connected to memory service!")
# List available tools
tools_response = await session.list_tools()
print(f"Found {len(tools_response.tools)} tools")
# Check if store_memory tool exists
if not any(tool.name == "store_memory" for tool in tools_response.tools):
print("ERROR: store_memory tool not found")
return
# Create a test memory
memory_data = {
"content": "This is a test memory created by the test_store_memory.py script.",
"metadata": {
"tags": "test,example,python", # Comma-separated string format
"type": "note"
}
}
# Store the memory
print(f"\nStoring test memory: {memory_data['content']}")
result = await session.call_tool("store_memory", memory_data)
# Print result
if result:
print("\nResult:")
for content_item in result.content:
if hasattr(content_item, 'text'):
print(content_item.text)
else:
print("No result returned")
# Try to retrieve the memory
print("\nRetrieving memory...")
retrieve_result = await session.call_tool("retrieve_memory", {"query": "test memory", "n_results": 5})
# Print result
if retrieve_result:
print("\nRetrieve Result:")
for content_item in retrieve_result.content:
if hasattr(content_item, 'text'):
print(content_item.text)
else:
print("No retrieve result returned")
# Check database health
print("\nChecking database health...")
health_result = await session.call_tool("check_database_health", {})
# Print result
if health_result:
print("\nHealth Check Result:")
for content_item in health_result.content:
if hasattr(content_item, 'text'):
print(content_item.text)
else:
print("No health check result returned")
except Exception as e:
print(f"ERROR: {str(e)}")
import traceback
traceback.print_exc()
async def main():
"""Main function."""
print("=== MCP Memory Service Test: Store Memory ===\n")
await store_memory()
if __name__ == "__main__":
asyncio.run(main())
```
--------------------------------------------------------------------------------
/.claude/directives/consolidation-details.md:
--------------------------------------------------------------------------------
```markdown
# Memory Consolidation System - Detailed Reference
**Quick Summary for CLAUDE.md**: See main file for architecture overview. This file contains performance expectations, configuration details, and operational procedures.
## Performance Expectations (Real-World)
Based on v8.23.1 test with 2,495 memories:
| Backend | First Run | Subsequent Runs | Notes |
|---------|-----------|----------------|-------|
| **SQLite-Vec** | 5-25s | 5-25s | Fast, local-only |
| **Cloudflare** | 2-4min | 1-3min | Network-dependent, cloud-only |
| **Hybrid** | 4-6min | 2-4min | Slower but provides multi-device sync |
**Why Hybrid takes longer**: Local SQLite operations (~5ms) + Cloudflare cloud sync (~150ms per update). Trade-off: Processing time for data persistence across devices.
**Recommendation**: Hybrid backend is recommended for production despite longer consolidation time.
## Complete Configuration
```bash
# Enable consolidation (default: true)
MCP_CONSOLIDATION_ENABLED=true
# Association-based quality boost (v8.47.0+)
MCP_CONSOLIDATION_QUALITY_BOOST_ENABLED=true # Enable boost (default: true)
MCP_CONSOLIDATION_MIN_CONNECTIONS_FOR_BOOST=5 # Min connections (default: 5)
MCP_CONSOLIDATION_QUALITY_BOOST_FACTOR=1.2 # Boost multiplier (default: 1.2 = 20%)
# Scheduler configuration (in config.py)
CONSOLIDATION_SCHEDULE = {
'daily': '02:00', # Daily at 2 AM
'weekly': 'SUN 03:00', # Weekly on Sunday at 3 AM
'monthly': '01 04:00', # Monthly on 1st at 4 AM
'quarterly': 'disabled', # Disabled
'yearly': 'disabled' # Disabled
}
```
## HTTP API Endpoints
| Endpoint | Method | Description | Response Time |
|----------|--------|-------------|---------------|
| `/api/consolidation/trigger` | POST | Trigger consolidation | ~10-30s |
| `/api/consolidation/status` | GET | Scheduler status | <5ms |
| `/api/consolidation/recommendations/{horizon}` | GET | Get recommendations | ~50ms |
**Example:**
```bash
# Trigger weekly consolidation
curl -X POST http://127.0.0.1:8000/api/consolidation/trigger \
-H "Content-Type: application/json" \
-d '{"time_horizon": "weekly"}'
# Check status
curl http://127.0.0.1:8000/api/consolidation/status
```
## Code Execution API (Token Efficiency)
```python
from mcp_memory_service.api import consolidate, scheduler_status
# Trigger consolidation (15 tokens vs 150 MCP tool - 90% reduction)
result = consolidate('weekly')
# Check scheduler (10 tokens vs 125 - 92% reduction)
status = scheduler_status()
```
## Features
- **Exponential decay scoring** - Prioritize recent, frequently accessed memories
- **Association-based quality boost** 🆕 - Well-connected memories (≥5 connections) get 20% quality boost
- **Creative association discovery** - Find semantic connections (0.3-0.7 similarity)
- **Semantic clustering** - Group related memories (DBSCAN algorithm)
- **Compression** - Summarize redundant information (preserves originals)
- **Controlled forgetting** - Archive low-relevance memories (90+ days inactive)
## Migration from MCP-only Mode (v8.22.x → v8.23.0+)
**No action required** - Consolidation automatically runs in HTTP server if enabled.
For users without HTTP server:
```bash
# Enable HTTP server in .env
export MCP_HTTP_ENABLED=true
# Restart service
systemctl --user restart mcp-memory-http.service
```
## Operational Guide
See [docs/guides/memory-consolidation-guide.md](../../docs/guides/memory-consolidation-guide.md) for:
- Detailed operational procedures
- Monitoring and metrics
- Troubleshooting
- Best practices
Wiki version: [Memory Consolidation System Guide](https://github.com/doobidoo/mcp-memory-service/wiki/Memory-Consolidation-System-Guide)
```
--------------------------------------------------------------------------------
/archive/setup-development/STARTUP_SETUP_GUIDE.md:
--------------------------------------------------------------------------------
```markdown
# MCP Memory Service Auto-Startup Setup Guide
## ✅ Files Created:
- `mcp-memory.service` - Systemd service configuration
- `install_service.sh` - Installation script
- `service_control.sh` - Service management script
- `STARTUP_SETUP_GUIDE.md` - This guide
## 🚀 Manual Installation Steps:
### 1. Install the systemd service:
```bash
# Run the installation script (requires sudo password)
sudo bash install_service.sh
```
### 2. Start the service immediately:
```bash
sudo systemctl start mcp-memory
```
### 3. Check service status:
```bash
sudo systemctl status mcp-memory
```
### 4. View service logs:
```bash
sudo journalctl -u mcp-memory -f
```
## 🛠️ Service Management Commands:
### Using the control script:
```bash
./service_control.sh start # Start service
./service_control.sh stop # Stop service
./service_control.sh restart # Restart service
./service_control.sh status # Show status
./service_control.sh logs # View live logs
./service_control.sh health # Test API health
./service_control.sh enable # Enable startup
./service_control.sh disable # Disable startup
```
### Using systemctl directly:
```bash
sudo systemctl start mcp-memory # Start now
sudo systemctl stop mcp-memory # Stop now
sudo systemctl restart mcp-memory # Restart now
sudo systemctl status mcp-memory # Check status
sudo systemctl enable mcp-memory # Enable startup (already done)
sudo systemctl disable mcp-memory # Disable startup
sudo journalctl -u mcp-memory -f # Live logs
```
## 📋 Service Configuration:
### Generated API Key:
```
mcp-83c9840168aac025986cc4bc29e411bb
```
### Service Details:
- **Service Name**: `mcp-memory.service`
- **User**: hkr
- **Working Directory**: `/home/hkr/repositories/mcp-memory-service`
- **Auto-restart**: Yes (on failure)
- **Startup**: Enabled (starts on boot)
### Environment Variables:
- `MCP_CONSOLIDATION_ENABLED=true`
- `MCP_MDNS_ENABLED=true`
- `MCP_HTTPS_ENABLED=true`
- `MCP_MDNS_SERVICE_NAME="MCP Memory"`
- `MCP_HTTP_HOST=0.0.0.0`
- `MCP_HTTP_PORT=8000`
- `MCP_MEMORY_STORAGE_BACKEND=sqlite_vec`
## 🌐 Access Points:
Once running, the service will be available at:
- **Dashboard**: https://localhost:8000
- **API Documentation**: https://localhost:8000/api/docs
- **Health Check**: https://localhost:8000/api/health
- **SSE Events**: https://localhost:8000/api/events
- **mDNS Name**: `MCP Memory._mcp-memory._tcp.local.`
## 🔧 Troubleshooting:
### If service fails to start:
```bash
# Check detailed logs
sudo journalctl -u mcp-memory --no-pager
# Check if virtual environment exists
ls -la /home/hkr/repositories/mcp-memory-service/venv/
# Test manual startup
cd /home/hkr/repositories/mcp-memory-service
source venv/bin/activate
python scripts/run_http_server.py
```
### If port 8000 is in use:
```bash
# Check what's using port 8000
sudo ss -tlnp | grep :8000
# Or change port in service file
sudo nano /etc/systemd/system/mcp-memory.service
# Edit: Environment=MCP_HTTP_PORT=8001
sudo systemctl daemon-reload
sudo systemctl restart mcp-memory
```
## 🗑️ Uninstallation:
To remove the service:
```bash
./service_control.sh uninstall
```
Or manually:
```bash
sudo systemctl stop mcp-memory
sudo systemctl disable mcp-memory
sudo rm /etc/systemd/system/mcp-memory.service
sudo systemctl daemon-reload
```
## ✅ Success Verification:
After installation, verify everything works:
```bash
# 1. Check service is running
sudo systemctl status mcp-memory
# 2. Test API health
curl -k https://localhost:8000/api/health
# 3. Check mDNS discovery
avahi-browse -t _mcp-memory._tcp
# 4. View live logs
sudo journalctl -u mcp-memory -f
```
The service will now start automatically on every system boot! 🎉
```
--------------------------------------------------------------------------------
/scripts/service/windows/uninstall_scheduled_task.ps1:
--------------------------------------------------------------------------------
```
#Requires -Version 5.1
<#
.SYNOPSIS
Uninstalls the MCP Memory HTTP Server scheduled task.
.DESCRIPTION
Stops the running server (if any) and removes the scheduled task from Windows Task Scheduler.
Optionally cleans up log files.
.PARAMETER CleanupLogs
Also remove log files from %LOCALAPPDATA%\mcp-memory\logs
.PARAMETER Force
Don't prompt for confirmation.
.EXAMPLE
.\uninstall_scheduled_task.ps1
Uninstalls the task (prompts for confirmation).
.EXAMPLE
.\uninstall_scheduled_task.ps1 -Force -CleanupLogs
Uninstalls without prompting and removes logs.
.NOTES
File Name : uninstall_scheduled_task.ps1
Location : scripts/service/windows/
#>
param(
[switch]$CleanupLogs,
[switch]$Force
)
$ErrorActionPreference = "Stop"
# Configuration
$TaskName = "MCPMemoryHTTPServer"
$LogDir = Join-Path $env:LOCALAPPDATA "mcp-memory\logs"
$PidFile = Join-Path $env:LOCALAPPDATA "mcp-memory\http-server.pid"
Write-Host "========================================" -ForegroundColor Cyan
Write-Host " MCP Memory HTTP Server - Uninstaller " -ForegroundColor Cyan
Write-Host "========================================" -ForegroundColor Cyan
Write-Host ""
# Check if task exists
$ExistingTask = Get-ScheduledTask -TaskName $TaskName -ErrorAction SilentlyContinue
if (-not $ExistingTask) {
Write-Host "[INFO] Task '$TaskName' is not installed." -ForegroundColor Yellow
exit 0
}
# Confirm uninstall
if (-not $Force) {
$Response = Read-Host "Are you sure you want to uninstall the MCP Memory HTTP Server task? (y/N)"
if ($Response -ne 'y' -and $Response -ne 'Y') {
Write-Host "[INFO] Uninstallation cancelled." -ForegroundColor Yellow
exit 0
}
}
# Stop running task
Write-Host "[INFO] Stopping running task..." -ForegroundColor Yellow
try {
Stop-ScheduledTask -TaskName $TaskName -ErrorAction SilentlyContinue
} catch {
# Task might not be running
}
# Kill any lingering Python process
if (Test-Path $PidFile) {
$StoredPid = Get-Content $PidFile -ErrorAction SilentlyContinue
if ($StoredPid) {
Write-Host "[INFO] Stopping server process (PID: $StoredPid)..." -ForegroundColor Yellow
Stop-Process -Id $StoredPid -Force -ErrorAction SilentlyContinue
}
Remove-Item $PidFile -Force -ErrorAction SilentlyContinue
}
# Also try to stop via port
try {
$Connection = Get-NetTCPConnection -LocalPort 8000 -ErrorAction SilentlyContinue | Where-Object { $_.State -eq "Listen" }
if ($Connection) {
Write-Host "[INFO] Stopping process listening on port 8000..." -ForegroundColor Yellow
Stop-Process -Id $Connection.OwningProcess -Force -ErrorAction SilentlyContinue
}
} catch {
# Port might not be in use
}
# Wait a moment for cleanup
Start-Sleep -Seconds 1
# Unregister the task
Write-Host "[INFO] Removing scheduled task..." -ForegroundColor Yellow
try {
Unregister-ScheduledTask -TaskName $TaskName -Confirm:$false
Write-Host "[SUCCESS] Scheduled task removed." -ForegroundColor Green
} catch {
Write-Host "[ERROR] Failed to remove scheduled task: $_" -ForegroundColor Red
exit 1
}
# Cleanup logs if requested
if ($CleanupLogs) {
Write-Host "[INFO] Cleaning up log files..." -ForegroundColor Yellow
if (Test-Path $LogDir) {
Remove-Item "$LogDir\http-server*" -Force -ErrorAction SilentlyContinue
Write-Host "[SUCCESS] Log files removed." -ForegroundColor Green
}
}
Write-Host ""
Write-Host "[SUCCESS] MCP Memory HTTP Server has been uninstalled." -ForegroundColor Green
Write-Host ""
Write-Host "Note: Your memory database and configuration are preserved." -ForegroundColor Cyan
Write-Host "To reinstall, run: .\install_scheduled_task.ps1" -ForegroundColor Cyan
```
--------------------------------------------------------------------------------
/archive/docs-removed-2025-08-23/claude-code-compatibility.md:
--------------------------------------------------------------------------------
```markdown
# Claude Code Compatibility Guide
## Overview
The MCP Memory Service FastAPI server v4.0.0-alpha.1 implements the official MCP protocol but has specific compatibility considerations with Claude Code's SSE client implementation.
## Current Status
### ✅ Working MCP Clients
- **Standard MCP Libraries**: Python `mcp` package, JavaScript MCP SDK
- **Claude Desktop**: Works with proper MCP configuration
- **Custom MCP Clients**: Any client implementing standard MCP protocol
- **HTTP API**: Full REST API access via port 8080
### ❌ Claude Code SSE Client Issue
**Problem**: Claude Code's SSE client has specific header and protocol requirements that don't match the FastMCP server implementation.
**Technical Details**:
- FastMCP server requires `Accept: application/json, text/event-stream` headers
- Claude Code's SSE client doesn't send the required header combination
- Server correctly rejects invalid SSE connections with proper error messages
**Error Symptoms**:
```bash
claude mcp list
# Output: memory: http://10.0.1.30:8000/mcp (SSE) - ✗ Failed to connect
```
## Workarounds for Claude Code Users
### Option 1: Use HTTP Dashboard
```bash
# Access memory service via web interface
open http://memory.local:8080/
# Use API endpoints directly
curl -X POST http://memory.local:8080/api/memories \
-H "Content-Type: application/json" \
-d '{"content": "My memory", "tags": ["important"]}'
```
### Option 2: Use Claude Commands (Recommended)
```bash
# Install Claude Code commands (bypass MCP entirely)
python install.py --install-claude-commands
# Use conversational memory commands
claude /memory-store "Important information"
claude /memory-recall "what did we discuss?"
claude /memory-search --tags "project,architecture"
```
### Option 3: Use Alternative MCP Client
```python
# Python example with standard MCP client
import asyncio
from mcp import ClientSession
from mcp.client.stdio import stdio_client
async def test_memory():
# This works with standard MCP protocol
# Implementation details for your specific needs
pass
```
## Technical Investigation Results
### Server Verification ✅
```bash
# Server correctly implements MCP protocol
curl -H "Accept: text/event-stream, application/json" \
-H "Content-Type: application/json" \
-X POST http://memory.local:8000/mcp \
-d '{"jsonrpc":"2.0","id":"test","method":"tools/list","params":{}}'
# Result: 200 OK, SSE stream established
```
### Claude Code Client Issue ❌
```bash
# Claude Code client fails header negotiation
# Missing required Accept header combination
# Connection rejected with 406 Not Acceptable
```
## Development Roadmap
### Short Term (Next Release)
- [ ] Investigate Claude Code's exact SSE client requirements
- [ ] Consider server-side compatibility layer
- [ ] Expand client compatibility testing
### Medium Term
- [ ] Custom SSE implementation for Claude Code compatibility
- [ ] Alternative transport protocols (WebSocket, HTTP long-polling)
- [ ] Client library development
### Long Term
- [ ] Collaborate with Claude Code team on SSE standardization
- [ ] MCP protocol enhancement proposals
- [ ] Universal client compatibility layer
## Conclusion
The FastAPI MCP migration successfully achieved its primary goals:
- ✅ SSL connectivity issues resolved
- ✅ Standard MCP protocol compliance
- ✅ Production-ready architecture
The Claude Code compatibility issue is a client-specific limitation that doesn't impact the core migration success. Users have multiple viable workarounds available.
## Support
- **HTTP Dashboard**: http://memory.local:8080/
- **Documentation**: See `DUAL_SERVICE_DEPLOYMENT.md`
- **Issues**: Report at https://github.com/doobidoo/mcp-memory-service/issues
- **Claude Commands**: See `docs/guides/claude-code-quickstart.md`
```
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.yml:
--------------------------------------------------------------------------------
```yaml
name: Feature Request
description: Suggest a new feature or enhancement
title: "[Feature]: "
labels: ["enhancement", "triage"]
body:
- type: markdown
attributes:
value: |
Thank you for suggesting a feature! Please provide details about your use case and proposed solution.
- type: textarea
id: problem
attributes:
label: Problem or Use Case
description: What problem does this feature solve? What are you trying to accomplish?
placeholder: |
I'm trying to... but currently the system doesn't support...
This would help with...
validations:
required: true
- type: textarea
id: solution
attributes:
label: Proposed Solution
description: How would you like this feature to work?
placeholder: |
Add a new MCP tool that allows...
The API endpoint should accept...
When the user runs...
validations:
required: true
- type: textarea
id: alternatives
attributes:
label: Alternatives Considered
description: What other approaches have you considered? How do you currently work around this?
placeholder: |
I've tried using... but it doesn't work because...
Other projects solve this by...
- type: dropdown
id: component
attributes:
label: Component Affected
description: Which part of the system would this feature affect?
options:
- Storage Backend (sqlite/cloudflare/hybrid)
- MCP Tools (memory operations)
- HTTP API (dashboard/REST endpoints)
- Document Ingestion (PDF/DOCX/PPTX)
- Claude Code Integration (hooks/commands)
- Configuration/Setup
- Documentation
- Testing/CI
- Other
validations:
required: true
- type: dropdown
id: priority
attributes:
label: Priority
description: How important is this feature to your workflow?
options:
- Critical (blocking my work)
- High (significant improvement)
- Medium (nice to have)
- Low (future consideration)
validations:
required: true
- type: textarea
id: examples
attributes:
label: Examples or Mockups
description: |
Provide examples of how this would work:
- API request/response examples
- CLI command examples
- UI mockups (for dashboard features)
- Code snippets
placeholder: |
# Example usage
claude /memory-export --format json --tags important
# Expected output
{"memories": [...], "count": 42}
render: shell
- type: textarea
id: impact
attributes:
label: Impact on Existing Functionality
description: Would this change affect existing features or require breaking changes?
placeholder: |
This would require...
Existing users would need to...
Backward compatibility...
- type: textarea
id: similar
attributes:
label: Similar Features in Other Projects
description: Are there similar features in other projects we can learn from?
placeholder: |
Project X implements this as...
Library Y has a similar API that works like...
- type: checkboxes
id: checks
attributes:
label: Pre-submission Checklist
description: Please verify you've completed these steps
options:
- label: I've searched existing issues and feature requests
required: true
- label: I've described a specific use case (not just "it would be nice")
required: true
- label: I've considered the impact on existing functionality
required: true
- label: I'm willing to help test this feature once implemented
required: false
```
--------------------------------------------------------------------------------
/scripts/validation/check_dev_setup.py:
--------------------------------------------------------------------------------
```python
#!/usr/bin/env python3
"""
Verify development environment setup for MCP Memory Service.
Detects common issues like stale venv packages vs updated source code.
Usage:
python scripts/validation/check_dev_setup.py
Exit codes:
0 - Development environment is correctly configured
1 - Critical issues detected (editable install missing or version mismatch)
"""
import sys
import os
from pathlib import Path
def check_editable_install():
"""Check if package is installed in editable mode."""
try:
import mcp_memory_service
package_location = Path(mcp_memory_service.__file__).parent
# Check if location is in source directory (editable) or site-packages
if 'site-packages' in str(package_location):
return False, str(package_location)
else:
return True, str(package_location)
except ImportError:
return None, "Package not installed"
def check_version_match():
"""Check if installed version matches source code version."""
# Read source version
repo_root = Path(__file__).parent.parent.parent
init_file = repo_root / "src" / "mcp_memory_service" / "__init__.py"
source_version = None
if not init_file.exists():
return None, "Unknown", "Source file not found"
with open(init_file) as f:
for line in f:
if line.startswith('__version__'):
source_version = line.split('=')[1].strip().strip('"\'')
break
# Get installed version
try:
import mcp_memory_service
installed_version = mcp_memory_service.__version__
except ImportError:
return None, source_version, "Not installed"
if source_version is None:
return None, "Unknown", installed_version
return source_version == installed_version, source_version, installed_version
def main():
print("=" * 70)
print("MCP Memory Service - Development Environment Check")
print("=" * 70)
has_error = False
# Check 1: Editable install
print("\n[1/2] Checking installation mode...")
is_editable, location = check_editable_install()
if is_editable is None:
print(" ❌ CRITICAL: Package not installed")
print(f" Location: {location}")
print("\n Fix: pip install -e .")
has_error = True
elif not is_editable:
print(" ⚠️ WARNING: Package installed in site-packages (not editable)")
print(f" Location: {location}")
print("\n This means source code changes won't take effect!")
print(" Fix: pip uninstall mcp-memory-service && pip install -e .")
has_error = True
else:
print(f" ✅ OK: Editable install detected")
print(f" Location: {location}")
# Check 2: Version match
print("\n[2/2] Checking version consistency...")
versions_match, source_ver, installed_ver = check_version_match()
if versions_match is None:
print(" ⚠️ WARNING: Could not determine versions")
print(f" Source: {source_ver}")
print(f" Installed: {installed_ver}")
elif not versions_match:
print(f" ❌ CRITICAL: Version mismatch detected!")
print(f" Source code: v{source_ver}")
print(f" Installed: v{installed_ver}")
print("\n This is the 'stale venv' issue!")
print(" Fix: pip install -e . --force-reinstall")
has_error = True
else:
print(f" ✅ OK: Versions match (v{source_ver})")
print("\n" + "=" * 70)
if has_error:
print("❌ Development environment has CRITICAL issues!")
print("=" * 70)
sys.exit(1)
else:
print("✅ Development environment is correctly configured!")
print("=" * 70)
sys.exit(0)
if __name__ == "__main__":
main()
```
--------------------------------------------------------------------------------
/docs/amp-cli-bridge.md:
--------------------------------------------------------------------------------
```markdown
# Amp CLI Bridge (Semi-Automated Workflow)
**Purpose**: Leverage Amp CLI capabilities (research, code analysis, web search) from Claude Code without consuming Claude Code credits, using a semi-automated file-based workflow.
## Quick Start
**1. Claude Code creates prompt**:
```
You: "Use @agent-amp-bridge to research TypeScript 5.0 features"
Claude: [Creates prompt file and shows command]
```
**2. Run the command shown**:
```bash
amp @.claude/amp/prompts/pending/research-xyz.json
```
**3. Amp processes and writes response automatically**
**4. Claude Code continues automatically**
## Architecture
```
Claude Code (@agent-amp-bridge) → .claude/amp/prompts/pending/{uuid}.json
↓
You run: amp @prompts/pending/{uuid}.json
↓
Amp writes: responses/ready/{uuid}.json
↓
Claude Code reads response ← Workflow continues
```
## File Structure
```
.claude/amp/
├── prompts/
│ └── pending/ # Prompts waiting for you to process
├── responses/
│ ├── ready/ # Responses written by Amp
│ └── consumed/ # Archive of processed responses
└── README.md # Documentation
```
## Message Format
**Prompt** (`.claude/amp/prompts/pending/{uuid}.json`):
```json
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"timestamp": "2025-11-04T20:00:00.000Z",
"prompt": "Research async/await best practices in Python",
"context": {
"project": "mcp-memory-service",
"cwd": "/path/to/project"
},
"options": {
"timeout": 300000,
"format": "markdown"
}
}
```
**Response** (`.claude/amp/responses/ready/{uuid}.json`):
```json
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"timestamp": "2025-11-04T20:05:00.000Z",
"success": true,
"output": "## Async/Await Best Practices\n\n...",
"error": null,
"duration": 300000
}
```
## Configuration
**File**: `.claude/amp/config.json`
```json
{
"pollInterval": 1000, // Check for new prompts every 1s
"timeout": 300000, // 5 minute timeout per prompt
"debug": false, // Enable debug logging
"ampCommand": "amp" // Amp CLI command
}
```
## Use Cases
- Web Research: "Research latest React 18 features"
- Code Analysis: "Analyze our storage backend architecture"
- Documentation: "Generate API docs for MCP tools"
- Code Generation: "Create TypeScript type definitions"
- Best Practices: "Find OAuth 2.1 security recommendations"
## Manual Inspection (Optional)
```bash
# List pending prompts
ls -lt .claude/amp/prompts/pending/
# View prompt content
cat .claude/amp/prompts/pending/{uuid}.json | jq -r '.prompt'
```
## Troubleshooting
**Amp CLI credit errors:**
```bash
# Test if Amp is authenticated
amp
# If credits exhausted, check status
# https://ampcode.com/settings
```
**Response not appearing:**
```bash
# Verify Amp wrote the file
ls -lt .claude/amp/responses/ready/
```
**Permission issues:**
```bash
# Ensure directories exist
ls -la .claude/amp/
# Check write permissions
touch .claude/amp/responses/ready/test.json && rm .claude/amp/responses/ready/test.json
```
## Benefits
- Zero Claude Code Credits: Uses your separate Amp session
- Uses Free Tier: Works with Amp's free tier (when credits available)
- Simple Workflow: No background processes
- Full Control: You decide when/what to process
- Fault Tolerant: File-based queue survives crashes
- Audit Trail: All prompts/responses saved
- Reusable: Can replay prompts or review past responses
## Limitations
- Manual Step Required: You must run the `amp @` command
- Amp Credits: Still consumes Amp API credits
- Semi-Async: Claude Code waits for you to process
- Best for Research: Optimized for async research tasks, not real-time chat
```
--------------------------------------------------------------------------------
/archive/docs-removed-2025-08-23/windows-setup.md:
--------------------------------------------------------------------------------
```markdown
# Windows Setup Guide for MCP Memory Service
This guide provides comprehensive instructions for setting up and running the MCP Memory Service on Windows systems, including handling common Windows-specific issues.
## Installation
### Prerequisites
- Python 3.10 or newer
- Git for Windows
- Visual Studio Build Tools (for PyTorch)
### Recommended Installation (Using UV)
1. Install UV:
```bash
pip install uv
```
2. Clone and setup:
```bash
git clone https://github.com/doobidoo/mcp-memory-service.git
cd mcp-memory-service
uv venv
.venv\Scripts\activate
uv pip install -r requirements.txt
uv pip install -e .
```
### Alternative: Windows-Specific Installation
If you encounter issues with UV, use our Windows-specific installation script:
```bash
python scripts/install_windows.py
```
This script handles:
1. Detecting CUDA availability
2. Installing the correct PyTorch version
3. Setting up dependencies without conflicts
4. Verifying the installation
## Configuration
### Claude Desktop Configuration
1. Create or edit your Claude Desktop configuration file:
- Location: `%APPDATA%\Claude\claude_desktop_config.json`
2. Add the following configuration:
```json
{
"memory": {
"command": "python",
"args": [
"C:\\path\\to\\mcp-memory-service\\memory_wrapper.py"
],
"env": {
"MCP_MEMORY_CHROMA_PATH": "C:\\Users\\YourUsername\\AppData\\Local\\mcp-memory\\chroma_db",
"MCP_MEMORY_BACKUPS_PATH": "C:\\Users\\YourUsername\\AppData\\Local\\mcp-memory\\backups"
}
}
}
```
### Environment Variables
Important Windows-specific environment variables:
```
MCP_MEMORY_USE_DIRECTML=1 # Enable DirectML acceleration if CUDA is not available
PYTORCH_ENABLE_MPS_FALLBACK=0 # Disable MPS (not needed on Windows)
```
## Common Windows-Specific Issues
### PyTorch Installation Issues
If you see errors about PyTorch installation:
1. Use the Windows-specific installation script:
```bash
python scripts/install_windows.py
```
2. Or manually install PyTorch with the correct index URL:
```bash
pip install torch==2.1.0 torchvision==2.1.0 torchaudio==2.1.0 --index-url https://download.pytorch.org/whl/cu118
```
### JSON Parsing Errors
If you see "Unexpected token" errors in Claude Desktop:
**Symptoms:**
```
Unexpected token 'U', "Using Chro"... is not valid JSON
Unexpected token 'I', "[INFO] Star"... is not valid JSON
```
**Solution:**
- Update to the latest version which includes Windows-specific stream handling fixes
- Use the memory wrapper script which properly handles stdout/stderr separation
### Recursion Errors
If you encounter recursion errors:
1. Run the sitecustomize fix script:
```bash
python scripts/fix_sitecustomize.py
```
2. Restart your Python environment
## Debugging Tools
Windows-specific debugging tools:
```bash
# Verify PyTorch installation
python scripts/verify_pytorch_windows.py
# Check environment compatibility
python scripts/verify_environment_enhanced.py
# Test the memory server
python scripts/run_memory_server.py
```
## Log Files
Important log locations on Windows:
- Claude Desktop logs: `%APPDATA%\Claude\logs\mcp-server-memory.log`
- Memory service logs: `%LOCALAPPDATA%\mcp-memory\logs\memory_service.log`
## Performance Optimization
### GPU Acceleration
1. CUDA (recommended if available):
- Ensure NVIDIA drivers are up to date
- CUDA toolkit is not required (bundled with PyTorch)
2. DirectML (alternative):
- Enable with `MCP_MEMORY_USE_DIRECTML=1`
- Useful for AMD GPUs or when CUDA is not available
### Memory Usage
If experiencing memory issues:
1. Reduce batch size:
```bash
set MCP_MEMORY_BATCH_SIZE=4
```
2. Use a smaller model:
```bash
set MCP_MEMORY_MODEL_NAME=paraphrase-MiniLM-L3-v2
```
## Getting Help
If you encounter Windows-specific issues:
1. Check the logs in `%APPDATA%\Claude\logs\`
2. Run verification tools mentioned above
3. Contact support via Telegram: t.me/doobeedoo
```
--------------------------------------------------------------------------------
/archive/docs-removed-2025-08-23/claude-code-quickstart.md:
--------------------------------------------------------------------------------
```markdown
# Claude Code Commands - Quick Start Guide
Get up and running with MCP Memory Service Claude Code commands in just 2 minutes!
## Prerequisites
✅ [Claude Code CLI](https://claude.ai/code) installed and working
✅ Python 3.10+ with pip
✅ 5 minutes of your time
## Step 1: Install MCP Memory Service with Commands
```bash
# Clone and install with Claude Code commands
git clone https://github.com/doobidoo/mcp-memory-service.git
cd mcp-memory-service
python install.py --install-claude-commands
```
The installer will:
- ✅ Detect your Claude Code CLI automatically
- ✅ Install the memory service with optimal settings for your system
- ✅ Install 5 conversational memory commands
- ✅ Test everything to ensure it works
## Step 2: Test Your Installation
```bash
# Check if everything is working
claude /memory-health
```
You should see a comprehensive health check interface. If you see the command description and interface, you're all set! 🎉
## Step 3: Store Your First Memory
```bash
# Store something important
claude /memory-store "I successfully set up MCP Memory Service with Claude Code commands on $(date)"
```
## Step 4: Try the Core Commands
```bash
# Recall memories by time
claude /memory-recall "what did I store today?"
# Search by content
claude /memory-search "MCP Memory Service"
# Capture current session context
claude /memory-context --summary "Initial setup and testing"
```
## 🎯 You're Done!
That's it! You now have powerful memory capabilities integrated directly into Claude Code.
## Available Commands
| Command | Purpose | Example |
|---------|---------|---------|
| `claude /memory-store` | Store information with context | `claude /memory-store "Important decision about architecture"` |
| `claude /memory-recall` | Retrieve by time expressions | `claude /memory-recall "what did we decide last week?"` |
| `claude /memory-search` | Search by tags or content | `claude /memory-search --tags "architecture,database"` |
| `claude /memory-context` | Capture session context | `claude /memory-context --summary "Planning session"` |
| `claude /memory-health` | Check service status | `claude /memory-health --detailed` |
## Next Steps
### Explore Advanced Features
- **Context-aware operations**: Commands automatically detect your current project
- **Smart tagging**: Automatic tag generation based on your work
- **Time-based queries**: Natural language like "yesterday", "last week", "two months ago"
- **Semantic search**: Find related information even with different wording
### Learn More
- 📖 [**Full Integration Guide**](claude-code-integration.md) - Complete documentation
- 🔧 [**Installation Master Guide**](../installation/master-guide.md) - Advanced installation options
- ❓ [**Troubleshooting**](../troubleshooting/general.md) - Solutions to common issues
## Troubleshooting Quick Fixes
### Commands Not Working?
```bash
# Check if Claude Code CLI is working
claude --version
# Check if commands are installed
ls ~/.claude/commands/memory-*.md
# Reinstall commands
python scripts/claude_commands_utils.py
```
### Memory Service Not Connecting?
```bash
# Check if service is running
memory --help
# Check service health
claude /memory-health
# Start the service if needed
memory
```
### Need Help?
- 💬 [GitHub Issues](https://github.com/doobidoo/mcp-memory-service/issues)
- 📚 [Full Documentation](../README.md)
- 🔍 [Search Existing Solutions](https://github.com/doobidoo/mcp-memory-service/issues?q=is%3Aissue)
---
## What Makes This Special?
🚀 **Zero Configuration**: No MCP server setup required
🧠 **Context Intelligence**: Understands your current project and session
💬 **Conversational Interface**: Natural, CCPlugins-compatible commands
⚡ **Instant Access**: Direct command-line memory operations
🛠️ **Professional Grade**: Enterprise-level capabilities through simple commands
**Enjoy your enhanced Claude Code experience with persistent memory!** 🎉
```
--------------------------------------------------------------------------------
/tests/integration/test_mcp_memory.py:
--------------------------------------------------------------------------------
```python
#\!/usr/bin/env python3
"""
Test script for MCP Memory Service with Homebrew PyTorch.
"""
import os
import sys
import asyncio
import time
from datetime import datetime
# Configure environment variables
os.environ["MCP_MEMORY_STORAGE_BACKEND"] = "sqlite_vec"
os.environ["MCP_MEMORY_SQLITE_PATH"] = os.path.expanduser("~/Library/Application Support/mcp-memory/sqlite_vec.db")
os.environ["MCP_MEMORY_BACKUPS_PATH"] = os.path.expanduser("~/Library/Application Support/mcp-memory/backups")
os.environ["MCP_MEMORY_USE_ONNX"] = "1"
# Import the MCP Memory Service modules
try:
from mcp_memory_service.storage.sqlite_vec import SqliteVecMemoryStorage
from mcp_memory_service.models.memory import Memory
from mcp_memory_service.utils.hashing import generate_content_hash
except ImportError as e:
print(f"Error importing MCP Memory Service modules: {e}")
sys.exit(1)
async def main():
print("=== MCP Memory Service Test ===")
# Initialize the storage
db_path = os.environ["MCP_MEMORY_SQLITE_PATH"]
print(f"Using SQLite-vec database at: {db_path}")
storage = SqliteVecMemoryStorage(db_path)
await storage.initialize()
# Check database health
print("\n=== Database Health Check ===")
if storage.conn is None:
print("Database connection is not initialized")
else:
try:
cursor = storage.conn.execute('SELECT COUNT(*) FROM memories')
memory_count = cursor.fetchone()[0]
print(f"Database connected successfully. Contains {memory_count} memories.")
cursor = storage.conn.execute("SELECT name FROM sqlite_master WHERE type='table'")
tables = [row[0] for row in cursor.fetchall()]
print(f"Database tables: {', '.join(tables)}")
print(f"Embedding model availability: {storage.embedding_model is not None}")
if not storage.embedding_model:
print("No embedding model available. Limited functionality.")
except Exception as e:
print(f"Database error: {str(e)}")
# Get database stats
print("\n=== Database Stats ===")
stats = storage.get_stats()
import json
print(json.dumps(stats, indent=2))
# Store a test memory
print("\n=== Creating Test Memory ===")
test_content = f"MCP Test memory created at {datetime.now().isoformat()} with Homebrew PyTorch"
test_memory = Memory(
content=test_content,
content_hash=generate_content_hash(test_content),
tags=["mcp-test", "homebrew-pytorch"],
memory_type="note",
metadata={"source": "mcp_test_script"}
)
print(f"Memory content: {test_memory.content}")
print(f"Content hash: {test_memory.content_hash}")
success, message = await storage.store(test_memory)
print(f"Store success: {success}")
print(f"Message: {message}")
# Try to retrieve the memory
print("\n=== Retrieving by Tag ===")
memories = await storage.search_by_tag(["mcp-test"])
if memories:
print(f"Found {len(memories)} memories with tag 'mcp-test'")
for i, memory in enumerate(memories):
print(f" Memory {i+1}: {memory.content[:60]}...")
else:
print("No memories found with tag 'mcp-test'")
# Try semantic search
print("\n=== Semantic Search ===")
results = await storage.retrieve("test memory homebrew pytorch", n_results=5)
if results:
print(f"Found {len(results)} memories via semantic search")
for i, result in enumerate(results):
print(f" Result {i+1}:")
print(f" Content: {result.memory.content[:60]}...")
print(f" Score: {result.relevance_score}")
else:
print("No memories found via semantic search")
print("\n=== Test Complete ===")
storage.close()
if __name__ == "__main__":
asyncio.run(main())
```
--------------------------------------------------------------------------------
/scripts/pr/amp_generate_tests.sh:
--------------------------------------------------------------------------------
```bash
#!/bin/bash
# scripts/pr/amp_generate_tests.sh - Generate pytest tests using Amp CLI
#
# Usage: bash scripts/pr/amp_generate_tests.sh <PR_NUMBER>
# Example: bash scripts/pr/amp_generate_tests.sh 215
set -e
PR_NUMBER=$1
if [ -z "$PR_NUMBER" ]; then
echo "Usage: $0 <PR_NUMBER>"
exit 1
fi
if ! command -v gh &> /dev/null; then
echo "Error: GitHub CLI (gh) is not installed"
exit 1
fi
echo "=== Amp CLI Test Generation for PR #$PR_NUMBER ==="
echo ""
# Ensure Amp directories exist
mkdir -p .claude/amp/prompts/pending
mkdir -p .claude/amp/responses/ready
mkdir -p /tmp/amp_tests
# Get changed Python files (excluding tests)
echo "Fetching changed files from PR #$PR_NUMBER..."
changed_files=$(gh pr diff $PR_NUMBER --name-only | grep '\.py$' | grep -v '^tests/' || echo "")
if [ -z "$changed_files" ]; then
echo "No Python files changed (excluding tests)."
exit 0
fi
echo "Changed Python files (non-test):"
echo "$changed_files"
echo ""
# Track UUIDs for all test generation tasks
test_uuids=()
for file in $changed_files; do
if [ ! -f "$file" ]; then
echo "Skipping $file (not found in working directory)"
continue
fi
echo "Creating test generation prompt for: $file"
# Generate UUID for this file's test generation
test_uuid=$(uuidgen 2>/dev/null || cat /proc/sys/kernel/random/uuid)
test_uuids+=("$test_uuid")
# Determine if test file already exists
base_name=$(basename "$file" .py)
test_file="tests/test_${base_name}.py"
if [ -f "$test_file" ]; then
existing_tests=$(cat "$test_file")
prompt_mode="append"
prompt_text="Existing test file exists. Analyze the existing tests and new/changed code to suggest ADDITIONAL pytest test cases. Only output new test functions to append to the existing file.\n\nExisting tests:\n${existing_tests}\n\nNew/changed code:\n$(cat "$file")\n\nProvide only new test functions (complete pytest syntax) that cover new functionality not already tested."
else
prompt_mode="create"
prompt_text="Generate comprehensive pytest tests for this Python module. Include: 1) Happy path tests, 2) Edge cases, 3) Error handling, 4) Async test cases if applicable. Output complete pytest test file.\n\nModule code:\n$(cat "$file")\n\nProvide complete test file content with imports, fixtures, and test functions."
fi
# Create test generation prompt
cat > .claude/amp/prompts/pending/tests-${test_uuid}.json << EOF
{
"id": "${test_uuid}",
"timestamp": "$(date -u +"%Y-%m-%dT%H:%M:%S.000Z")",
"prompt": "${prompt_text}",
"context": {
"project": "mcp-memory-service",
"task": "test-generation",
"pr_number": "${PR_NUMBER}",
"source_file": "${file}",
"test_file": "${test_file}",
"mode": "${prompt_mode}"
},
"options": {
"timeout": 180000,
"format": "python"
}
}
EOF
echo " ✅ Created prompt for ${file} (${prompt_mode} mode)"
done
echo ""
echo "=== Created ${#test_uuids[@]} test generation prompts ==="
echo ""
# Show Amp commands to run
echo "=== Run these Amp commands (can run in parallel) ==="
for uuid in "${test_uuids[@]}"; do
echo "amp @.claude/amp/prompts/pending/tests-${uuid}.json &"
done
echo ""
echo "=== Or use this one-liner to run all in background ==="
parallel_cmd=""
for uuid in "${test_uuids[@]}"; do
parallel_cmd+="(amp @.claude/amp/prompts/pending/tests-${uuid}.json > /tmp/amp-test-${uuid}.log 2>&1 &); "
done
parallel_cmd+="sleep 10 && bash scripts/pr/amp_collect_results.sh --timeout 300 --uuids '$(IFS=,; echo "${test_uuids[*]}")'"
echo "$parallel_cmd"
echo ""
# Save UUIDs for later collection
echo "$(IFS=,; echo "${test_uuids[*]}")" > /tmp/amp_test_generation_uuids_${PR_NUMBER}.txt
echo "UUIDs saved to /tmp/amp_test_generation_uuids_${PR_NUMBER}.txt"
echo ""
echo "After Amp completes, tests will be in .claude/amp/responses/consumed/"
echo "Extract test content and review before committing to tests/ directory"
```
--------------------------------------------------------------------------------
/scripts/run/run_mcp_memory.sh:
--------------------------------------------------------------------------------
```bash
#!/bin/bash
# Run MCP Memory Service with Homebrew PyTorch Integration for use with MCP
# Set paths
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
DB_DIR="$HOME/Library/Application Support/mcp-memory"
# Use environment variables if set, otherwise use defaults
DB_PATH="${MCP_MEMORY_SQLITE_PATH:-$DB_DIR/sqlite_vec.db}"
BACKUPS_PATH="${MCP_MEMORY_BACKUPS_PATH:-$DB_DIR/backups}"
# Extract directory parts
DB_DIR="$(dirname "$DB_PATH")"
BACKUPS_DIR="$(dirname "$BACKUPS_PATH")"
# Create directories if they don't exist
mkdir -p "$DB_DIR"
mkdir -p "$BACKUPS_DIR"
# Set environment variables (only if not already set)
export MCP_MEMORY_STORAGE_BACKEND="${MCP_MEMORY_STORAGE_BACKEND:-sqlite_vec}"
export MCP_MEMORY_SQLITE_PATH="$DB_PATH"
export MCP_MEMORY_BACKUPS_PATH="$BACKUPS_PATH"
export MCP_MEMORY_USE_ONNX="${MCP_MEMORY_USE_ONNX:-1}"
export MCP_MEMORY_USE_HOMEBREW_PYTORCH="${MCP_MEMORY_USE_HOMEBREW_PYTORCH:-1}"
# Check if we're running in Claude Desktop (indicated by a special env var we'll set)
if [ "${CLAUDE_DESKTOP_ENV:-}" = "1" ]; then
echo "🖥️ Running in Claude Desktop environment, skipping Homebrew PyTorch check" >&2
SKIP_HOMEBREW_CHECK=1
else
SKIP_HOMEBREW_CHECK=0
fi
# Check if Homebrew PyTorch is installed, unless skipped
if [ "$SKIP_HOMEBREW_CHECK" = "0" ]; then
if ! brew list | grep -q pytorch; then
echo "❌ ERROR: PyTorch is not installed via Homebrew." >&2
echo "Please install PyTorch first: brew install pytorch" >&2
exit 1
else
echo "✅ Homebrew PyTorch found" >&2
fi
fi
# Skip Homebrew-related checks if running in Claude Desktop
if [ "$SKIP_HOMEBREW_CHECK" = "0" ]; then
# Check if sentence-transformers is installed in Homebrew Python
HOMEBREW_PYTHON="$(brew --prefix pytorch)/libexec/bin/python3"
echo "Checking for sentence-transformers in $HOMEBREW_PYTHON..." >&2
# Use proper Python syntax with newlines for the import check
if ! $HOMEBREW_PYTHON -c "
try:
import sentence_transformers
print('Success: sentence-transformers is installed')
except ImportError as e:
print(f'Error: {e}')
exit(1)
" 2>&1 | grep -q "Success"; then
echo "⚠️ WARNING: sentence-transformers is not installed in Homebrew Python." >&2
echo "Installing sentence-transformers in Homebrew Python..." >&2
$HOMEBREW_PYTHON -m pip install sentence-transformers >&2
else
echo "✅ sentence-transformers is already installed in Homebrew Python" >&2
fi
else
echo "🖥️ Skipping sentence-transformers check in Claude Desktop environment" >&2
# Set a default Python path for reference in the log
HOMEBREW_PYTHON="/usr/bin/python3"
fi
# Activate virtual environment if it exists
if [ -d "$SCRIPT_DIR/venv" ]; then
source "$SCRIPT_DIR/venv/bin/activate"
echo "✅ Activated virtual environment" >&2
else
echo "⚠️ No virtual environment found at $SCRIPT_DIR/venv" >&2
echo " Running with system Python" >&2
fi
# Redirect all informational output to stderr to avoid JSON parsing errors
echo "========================================================" >&2
echo " MCP Memory Service with Homebrew PyTorch Integration" >&2
echo "========================================================" >&2
echo "Storage backend: $MCP_MEMORY_STORAGE_BACKEND" >&2
echo "SQLite-vec database: $MCP_MEMORY_SQLITE_PATH" >&2
echo "Backups path: $MCP_MEMORY_BACKUPS_PATH" >&2
echo "Homebrew Python: $HOMEBREW_PYTHON" >&2
echo "ONNX Runtime enabled: ${MCP_MEMORY_USE_ONNX:-No}" >&2
echo "Homebrew PyTorch enabled: ${MCP_MEMORY_USE_HOMEBREW_PYTORCH:-No}" >&2
echo "========================================================" >&2
# Ensure our source code is in the PYTHONPATH
export PYTHONPATH="$SCRIPT_DIR:$SCRIPT_DIR/src:$PYTHONPATH"
echo "PYTHONPATH: $PYTHONPATH" >&2
# Start the memory server with Homebrew PyTorch integration
echo "Starting MCP Memory Service..." >&2
python -m mcp_memory_service.homebrew_server "$@"
```
--------------------------------------------------------------------------------
/scripts/benchmarks/benchmark_code_execution_api.py:
--------------------------------------------------------------------------------
```python
#!/usr/bin/env python
"""
Benchmark script for Code Execution Interface API.
Measures token efficiency and performance of the new code execution API
compared to traditional MCP tool calls.
Usage:
python scripts/benchmarks/benchmark_code_execution_api.py
"""
import time
import sys
from pathlib import Path
# Add parent directory to path
sys.path.insert(0, str(Path(__file__).parent.parent.parent / "src"))
from mcp_memory_service.api import search, store, health
def estimate_tokens(text: str) -> int:
"""Rough token estimate: 1 token ≈ 4 characters."""
return len(text) // 4
def benchmark_search():
"""Benchmark search operation."""
print("\n=== Search Operation Benchmark ===")
# Store some test data
for i in range(10):
store(f"Test memory {i} for benchmarking", tags=["benchmark", "test"])
# Warm up
search("benchmark", limit=1)
# Benchmark cold call
start = time.perf_counter()
results = search("benchmark test", limit=5)
cold_ms = (time.perf_counter() - start) * 1000
# Benchmark warm calls
warm_times = []
for _ in range(10):
start = time.perf_counter()
results = search("benchmark test", limit=5)
warm_times.append((time.perf_counter() - start) * 1000)
avg_warm_ms = sum(warm_times) / len(warm_times)
# Estimate tokens
result_str = str(results.memories)
tokens = estimate_tokens(result_str)
print(f"Results: {results.total} memories found")
print(f"Cold call: {cold_ms:.1f}ms")
print(f"Warm call (avg): {avg_warm_ms:.1f}ms")
print(f"Token estimate: {tokens} tokens")
print(f"MCP comparison: ~2,625 tokens (85% reduction)")
def benchmark_store():
"""Benchmark store operation."""
print("\n=== Store Operation Benchmark ===")
# Warm up
store("Warmup memory", tags=["warmup"])
# Benchmark warm calls
warm_times = []
for i in range(10):
start = time.perf_counter()
hash_val = store(f"Benchmark memory {i}", tags=["benchmark"])
warm_times.append((time.perf_counter() - start) * 1000)
avg_warm_ms = sum(warm_times) / len(warm_times)
# Estimate tokens
param_str = "store('content', tags=['tag1', 'tag2'])"
tokens = estimate_tokens(param_str)
print(f"Warm call (avg): {avg_warm_ms:.1f}ms")
print(f"Token estimate: {tokens} tokens")
print(f"MCP comparison: ~150 tokens (90% reduction)")
def benchmark_health():
"""Benchmark health operation."""
print("\n=== Health Operation Benchmark ===")
# Benchmark warm calls
warm_times = []
for _ in range(10):
start = time.perf_counter()
info = health()
warm_times.append((time.perf_counter() - start) * 1000)
avg_warm_ms = sum(warm_times) / len(warm_times)
# Estimate tokens
info = health()
info_str = str(info)
tokens = estimate_tokens(info_str)
print(f"Status: {info.status}")
print(f"Backend: {info.backend}")
print(f"Count: {info.count}")
print(f"Warm call (avg): {avg_warm_ms:.1f}ms")
print(f"Token estimate: {tokens} tokens")
print(f"MCP comparison: ~125 tokens (84% reduction)")
def main():
"""Run all benchmarks."""
print("=" * 60)
print("Code Execution Interface API Benchmarks")
print("=" * 60)
try:
benchmark_search()
benchmark_store()
benchmark_health()
print("\n" + "=" * 60)
print("Summary")
print("=" * 60)
print("✅ All benchmarks completed successfully")
print("\nKey Findings:")
print("- Search: 85%+ token reduction vs MCP tools")
print("- Store: 90%+ token reduction vs MCP tools")
print("- Health: 84%+ token reduction vs MCP tools")
print("- Performance: <50ms cold, <10ms warm calls")
except Exception as e:
print(f"\n❌ Benchmark failed: {e}")
import traceback
traceback.print_exc()
sys.exit(1)
if __name__ == "__main__":
main()
```
--------------------------------------------------------------------------------
/.github/workflows/SECRET_CONDITIONAL_FIX.md:
--------------------------------------------------------------------------------
```markdown
# GitHub Actions Secret Conditional Logic Fix
## Critical Issue Resolved
**Date**: 2024-08-24
**Problem**: Workflows failing due to incorrect secret checking syntax in conditionals
### Root Cause
GitHub Actions does not support checking if secrets are empty using `!= ''` or `== ''` in conditional expressions.
### Incorrect Syntax (BROKEN)
```yaml
# ❌ This syntax doesn't work in GitHub Actions
if: matrix.registry == 'docker.io' && secrets.DOCKER_USERNAME != '' && secrets.DOCKER_PASSWORD != ''
# ❌ This also doesn't work
if: matrix.registry == 'docker.io' && (secrets.DOCKER_USERNAME == '' || secrets.DOCKER_PASSWORD == '')
```
### Correct Syntax (FIXED)
```yaml
# ✅ Check if secrets exist (truthy check)
if: matrix.registry == 'docker.io' && secrets.DOCKER_USERNAME && secrets.DOCKER_PASSWORD
# ✅ Check if secrets don't exist (falsy check)
if: matrix.registry == 'docker.io' && (!secrets.DOCKER_USERNAME || !secrets.DOCKER_PASSWORD)
```
## Changes Applied
### 1. main-optimized.yml - Line 286
**Before:**
```yaml
- name: Log in to Docker Hub
if: matrix.registry == 'docker.io' && secrets.DOCKER_USERNAME != '' && secrets.DOCKER_PASSWORD != ''
```
**After:**
```yaml
- name: Log in to Docker Hub
if: matrix.registry == 'docker.io' && secrets.DOCKER_USERNAME && secrets.DOCKER_PASSWORD
```
### 2. main-optimized.yml - Line 313
**Before:**
```yaml
- name: Build and push Docker image
if: matrix.registry == 'ghcr.io' || (matrix.registry == 'docker.io' && secrets.DOCKER_USERNAME != '' && secrets.DOCKER_PASSWORD != '')
```
**After:**
```yaml
- name: Build and push Docker image
if: matrix.registry == 'ghcr.io' || (matrix.registry == 'docker.io' && secrets.DOCKER_USERNAME && secrets.DOCKER_PASSWORD)
```
### 3. main-optimized.yml - Line 332
**Before:**
```yaml
- name: Docker Hub push skipped
if: matrix.registry == 'docker.io' && (secrets.DOCKER_USERNAME == '' || secrets.DOCKER_PASSWORD == '')
```
**After:**
```yaml
- name: Docker Hub push skipped
if: matrix.registry == 'docker.io' && (!secrets.DOCKER_USERNAME || !secrets.DOCKER_PASSWORD)
```
## How GitHub Actions Handles Secrets in Conditionals
### Secret Behavior
- **Exists**: `secrets.SECRET_NAME` evaluates to truthy
- **Missing/Empty**: `secrets.SECRET_NAME` evaluates to falsy
- **Cannot compare**: Direct string comparison with `!= ''` fails
### Recommended Patterns
```yaml
# Check if secret exists
if: secrets.MY_SECRET
# Check if secret doesn't exist
if: !secrets.MY_SECRET
# Check multiple secrets exist
if: secrets.SECRET1 && secrets.SECRET2
# Check if any secret is missing
if: !secrets.SECRET1 || !secrets.SECRET2
# Combine with other conditions
if: github.event_name == 'push' && secrets.MY_SECRET
```
## Impact
### Before Fix
- ✗ Workflows failed immediately at conditional evaluation
- ✗ Error: Invalid conditional syntax
- ✗ No Docker Hub operations could run
### After Fix
- ✅ Conditionals evaluate correctly
- ✅ Docker Hub steps run when credentials exist
- ✅ GHCR steps always run (no credentials needed)
- ✅ Skip messages show when credentials missing
## Alternative Approaches
### Option 1: Environment Variable Check
```yaml
env:
HAS_DOCKER_CREDS: ${{ secrets.DOCKER_USERNAME != null && secrets.DOCKER_PASSWORD != null }}
steps:
- name: Login
if: env.HAS_DOCKER_CREDS == 'true'
```
### Option 2: Continue on Error
```yaml
- name: Log in to Docker Hub
continue-on-error: true
uses: docker/login-action@v3
```
### Option 3: Job-Level Conditional
```yaml
jobs:
docker-hub-publish:
if: secrets.DOCKER_USERNAME && secrets.DOCKER_PASSWORD
```
## Testing
All changes validated:
- ✅ YAML syntax check passed
- ✅ Conditional logic follows GitHub Actions standards
- ✅ Both positive and negative conditionals fixed
## References
- [GitHub Actions: Expressions](https://docs.github.com/en/actions/learn-github-actions/expressions)
- [GitHub Actions: Contexts](https://docs.github.com/en/actions/learn-github-actions/contexts#secrets-context)
Date: 2024-08-24
Status: Fixed and ready for deployment
```
--------------------------------------------------------------------------------
/docs/technical/sqlite-vec-embedding-fixes.md:
--------------------------------------------------------------------------------
```markdown
# SQLite-vec Embedding Fixes
This document summarizes the fixes applied to resolve issue #64 where semantic search returns 0 results in the SQLite-vec backend.
## Root Causes Identified
1. **Missing Core Dependencies**: `sentence-transformers` and `torch` were in optional dependencies, causing silent failures
2. **Dimension Mismatch**: Vector table was created with hardcoded dimensions before model initialization
3. **Silent Failures**: Missing dependencies returned zero vectors without raising exceptions
4. **Database Integrity Issues**: Potential rowid misalignment between memories and embeddings tables
## Changes Made
### 1. Fixed Dependencies (pyproject.toml)
- Moved `sentence-transformers>=2.2.2` from optional to core dependencies
- Added `torch>=1.6.0` to core dependencies
- This ensures embedding functionality is always available
### 2. Fixed Initialization Order (sqlite_vec.py)
- Moved embedding model initialization BEFORE vector table creation
- This ensures the correct embedding dimension is used for the table schema
- Added explicit check for sentence-transformers availability
### 3. Improved Error Handling
- Replaced silent failures with explicit exceptions
- Added proper error messages for missing dependencies
- Added embedding validation after generation (dimension check, finite values check)
### 4. Fixed Database Operations
#### Store Operation:
- Added try-catch for embedding generation with proper error propagation
- Added fallback for rowid insertion if direct rowid insert fails
- Added validation before storing embeddings
#### Retrieve Operation:
- Added check for empty embeddings table
- Added debug logging for troubleshooting
- Improved error handling for query embedding generation
### 5. Created Diagnostic Script
- `scripts/test_sqlite_vec_embeddings.py` - comprehensive test suite
- Tests dependencies, initialization, embedding generation, storage, and search
- Provides clear error messages and troubleshooting guidance
## Key Code Changes
### sqlite_vec.py:
1. **Initialize method**:
- Added sentence-transformers check
- Moved model initialization before table creation
2. **_generate_embedding method**:
- Raises exception instead of returning zero vector
- Added comprehensive validation
3. **store method**:
- Better error handling for embedding generation
- Fallback for rowid insertion
4. **retrieve method**:
- Check for empty embeddings table
- Better debug logging
## Testing
Run the diagnostic script to verify the fixes:
```bash
python3 scripts/test_sqlite_vec_embeddings.py
```
This will check:
- Dependency installation
- Storage initialization
- Embedding generation
- Memory storage with embeddings
- Semantic search functionality
- Database integrity
## Migration Notes
For existing installations:
1. Update dependencies: `uv pip install -e .`
2. Use the provided migration tools to save existing memories:
### Option 1: Quick Repair (Try First)
For databases with missing embeddings but correct schema:
```bash
python3 scripts/repair_sqlite_vec_embeddings.py /path/to/your/sqlite_vec.db
```
This will:
- Analyze your database
- Generate missing embeddings
- Verify search functionality
### Option 2: Full Migration (If Repair Fails)
For databases with dimension mismatches or schema issues:
```bash
python3 scripts/migrate_sqlite_vec_embeddings.py /path/to/your/sqlite_vec.db
```
This will:
- Create a backup of your database
- Extract all memories
- Create a new database with correct schema
- Regenerate all embeddings
- Restore all memories
**Important**: The migration creates a timestamped backup before making any changes.
## Future Improvements
1. ~~Add migration script for existing databases~~ ✓ Done
2. Add batch embedding generation for better performance
3. ~~Add embedding regeneration capability for existing memories~~ ✓ Done
4. Implement better rowid synchronization between tables
5. Add automatic detection and repair on startup
6. Add embedding model versioning to handle model changes
```