#
tokens: 48985/50000 24/625 files (page 8/35)
lines: off (toggle) GitHub
raw markdown copy
This is page 8 of 35. Use http://codebase.md/doobidoo/mcp-memory-service?lines=false&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
│   ├── settings.local.json.backup
│   └── settings.local.json.local
├── .commit-message
├── .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-code-review.yml
│       ├── claude.yml
│       ├── cleanup-images.yml.disabled
│       ├── dev-setup-validation.yml
│       ├── docker-publish.yml
│       ├── LATEST_FIXES.md
│       ├── main-optimized.yml.disabled
│       ├── main.yml
│       ├── publish-and-test.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
├── .pyscn
│   ├── .gitignore
│   └── reports
│       └── analyze_20251123_214224.html
├── AGENTS.md
├── 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
│   │   ├── memory-retrieval.js
│   │   ├── mid-conversation.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-NATURAL-TRIGGERS.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-session-tracking.json
│   │   └── test-threading.json
│   ├── utilities
│   │   ├── adaptive-pattern-detector.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-tracker.js
│   │   ├── tiered-conversation-monitor.js
│   │   └── version-checker.js
│   └── WINDOWS-SESSIONSTART-BUG.md
├── CLAUDE.md
├── CODE_OF_CONDUCT.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
│   │   ├── 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
│   ├── 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-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
│   │   └── tag-schema.json
│   ├── 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
│   │   ├── 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
│   ├── 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
│   ├── 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
│   ├── natural-memory-triggers
│   │   ├── cli-reference.md
│   │   ├── installation-guide.md
│   │   └── performance-optimization.md
│   ├── oauth-setup.md
│   ├── pr-graphql-integration.md
│   ├── quick-setup-cloudflare-dual-environment.md
│   ├── README.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
│   │   ├── general.md
│   │   ├── hooks-quick-reference.md
│   │   ├── pr162-schema-caching-issue.md
│   │   ├── session-end-hooks.md
│   │   └── sync-issues.md
│   └── tutorials
│       ├── advanced-techniques.md
│       ├── data-analysis.md
│       └── demo-session-walkthrough.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
├── install_service.py
├── install.py
├── LICENSE
├── NOTICE
├── pyproject.toml
├── pytest.ini
├── README.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
│   ├── 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
│   │   ├── assign_memory_types.py
│   │   ├── check_memory_types.py
│   │   ├── cleanup_corrupted_encoding.py
│   │   ├── cleanup_memories.py
│   │   ├── cleanup_organize.py
│   │   ├── consolidate_memory_types.py
│   │   ├── consolidation_mappings.json
│   │   ├── delete_orphaned_vectors_fixed.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
│   │   └── scan_todos.sh
│   ├── 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
│   │   ├── quality_gate.sh
│   │   ├── resolve_threads.sh
│   │   ├── run_pyscn_analysis.sh
│   │   ├── run_quality_checks.sh
│   │   ├── thread_status.sh
│   │   └── watch_reviews.sh
│   ├── quality
│   │   ├── fix_dead_code_install.sh
│   │   ├── phase1_dead_code_analysis.md
│   │   ├── phase2_complexity_analysis.md
│   │   ├── README_PHASE1.md
│   │   ├── README_PHASE2.md
│   │   ├── track_pyscn_metrics.sh
│   │   └── weekly_quality_review.sh
│   ├── README.md
│   ├── run
│   │   ├── 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
│   │   ├── install_http_service.sh
│   │   ├── mcp-memory-http.service
│   │   ├── mcp-memory.service
│   │   ├── memory_service_manager.sh
│   │   ├── service_control.sh
│   │   ├── service_utils.py
│   │   └── update_service.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
│   ├── utils
│   │   ├── claude_commands_utils.py
│   │   ├── generate_personalized_claude_md.sh
│   │   ├── groq
│   │   ├── groq_agent_bridge.py
│   │   ├── list-collections.py
│   │   ├── memory_wrapper_uv.py
│   │   ├── query_memories.py
│   │   ├── smithery_wrapper.py
│   │   ├── test_groq_bridge.sh
│   │   └── uv_wrapper.py
│   └── validation
│       ├── check_dev_setup.py
│       ├── check_documentation_links.py
│       ├── diagnose_backend_config.py
│       ├── validate_configuration_complete.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
│       ├── 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
│       ├── server.py
│       ├── services
│       │   ├── __init__.py
│       │   └── memory_service.py
│       ├── storage
│       │   ├── __init__.py
│       │   ├── base.py
│       │   ├── cloudflare.py
│       │   ├── factory.py
│       │   ├── http_client.py
│       │   ├── hybrid.py
│       │   └── 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
│       │   ├── document_processing.py
│       │   ├── gpu_detection.py
│       │   ├── hashing.py
│       │   ├── http_server_manager.py
│       │   ├── port_detection.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
│           │   ├── 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
│               ├── index.html
│               ├── README.md
│               ├── sse_test.html
│               └── style.css
├── start_http_debug.bat
├── start_http_server.sh
├── test_document.txt
├── test_version_checker.js
├── 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
│   ├── contracts
│   │   └── api-specification.yml
│   ├── integration
│   │   ├── package-lock.json
│   │   ├── package.json
│   │   ├── 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
│   ├── test_client.py
│   ├── test_content_splitting.py
│   ├── test_database.py
│   ├── test_hybrid_cloudflare_limits.py
│   ├── test_hybrid_storage.py
│   ├── test_memory_ops.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_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
├── 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
```

# Files

--------------------------------------------------------------------------------
/docs/oauth-setup.md:
--------------------------------------------------------------------------------

```markdown
# OAuth 2.1 Dynamic Client Registration Setup

This guide explains how to configure and use OAuth 2.1 Dynamic Client Registration with MCP Memory Service to enable Claude Code HTTP transport integration.

## Overview

The MCP Memory Service now supports OAuth 2.1 Dynamic Client Registration (DCR) as specified in RFC 7591. This enables:

- **Claude Code HTTP Transport**: Direct integration with Claude Code's team collaboration features
- **Automated Client Registration**: Clients can register themselves without manual configuration
- **Secure Authentication**: JWT-based access tokens with proper scope validation
- **Backward Compatibility**: Existing API key authentication continues to work

## Quick Start

### 1. Enable OAuth

Set the OAuth environment variable:

```bash
export MCP_OAUTH_ENABLED=true
```

### 2. Start the Server

```bash
# Start with OAuth enabled
uv run memory server --http

# Or with HTTPS (recommended for production)
export MCP_HTTPS_ENABLED=true
export MCP_SSL_CERT_FILE=/path/to/cert.pem
export MCP_SSL_KEY_FILE=/path/to/key.pem
uv run memory server --http
```

### 3. Test OAuth Endpoints

```bash
# Test the OAuth implementation
python tests/integration/test_oauth_flow.py http://localhost:8000
```

## Configuration

### Environment Variables

| Variable | Default | Description |
|----------|---------|-------------|
| `MCP_OAUTH_ENABLED` | `true` | Enable/disable OAuth 2.1 endpoints |
| `MCP_OAUTH_SECRET_KEY` | Auto-generated | JWT signing key (set for persistence) |
| `MCP_OAUTH_ISSUER` | Auto-detected | OAuth issuer URL |
| `MCP_OAUTH_ACCESS_TOKEN_EXPIRE_MINUTES` | `60` | Access token lifetime |
| `MCP_OAUTH_AUTHORIZATION_CODE_EXPIRE_MINUTES` | `10` | Authorization code lifetime |

### Example Configuration

```bash
# Production configuration
export MCP_OAUTH_ENABLED=true
export MCP_OAUTH_SECRET_KEY="your-secure-secret-key-here"
export MCP_OAUTH_ISSUER="https://your-domain.com"
export MCP_HTTPS_ENABLED=true

# Development configuration
export MCP_OAUTH_ENABLED=true
export MCP_OAUTH_ISSUER="http://localhost:8000"  # Match server port
```

## OAuth Endpoints

### Discovery Endpoints

- `GET /.well-known/oauth-authorization-server/mcp` - OAuth server metadata
- `GET /.well-known/openid-configuration/mcp` - OpenID Connect discovery

### OAuth Flow Endpoints

- `POST /oauth/register` - Dynamic client registration
- `GET /oauth/authorize` - Authorization endpoint
- `POST /oauth/token` - Token endpoint

### Management Endpoints

- `GET /oauth/clients/{client_id}` - Client information (debugging)

## Claude Code Integration

### Automatic Setup

Claude Code will automatically discover and register with the OAuth server:

1. **Discovery**: Claude Code requests `/.well-known/oauth-authorization-server/mcp`
2. **Registration**: Automatically registers as an OAuth client
3. **Authorization**: Redirects user for authorization (auto-approved in MVP)
4. **Token Exchange**: Exchanges authorization code for access token
5. **API Access**: Uses Bearer token for all HTTP transport requests

### Manual Configuration

If needed, you can manually configure Claude Code:

```json
{
  "memoryService": {
    "protocol": "http",
    "http": {
      "endpoint": "http://localhost:8000",  # Use actual server endpoint
      "oauth": {
        "enabled": true,
        "discoveryUrl": "http://localhost:8000/.well-known/oauth-authorization-server/mcp"
      }
    }
  }
}
```

## API Authentication

### Bearer Token Authentication

All API endpoints support Bearer token authentication:

```bash
# Get access token via OAuth flow
export ACCESS_TOKEN="your-jwt-access-token"

# Use Bearer token for API requests
curl -H "Authorization: Bearer $ACCESS_TOKEN" \
     http://localhost:8000/api/memories
```

### Scope-Based Authorization

The OAuth system supports three scopes:

- **`read`**: Access to read-only endpoints
- **`write`**: Access to create/update endpoints
- **`admin`**: Access to administrative endpoints

### Backward Compatibility

API key authentication continues to work:

```bash
# Legacy API key authentication
export MCP_API_KEY="your-api-key"
curl -H "Authorization: Bearer $MCP_API_KEY" \
     http://localhost:8000/api/memories
```

## Security Considerations

### Production Deployment

1. **Use HTTPS**: Always enable HTTPS in production
2. **Set Secret Key**: Provide a secure `MCP_OAUTH_SECRET_KEY`
3. **Secure Storage**: Consider persistent client storage for production
4. **Rate Limiting**: Implement rate limiting on OAuth endpoints

### OAuth 2.1 Compliance

The implementation follows OAuth 2.1 security requirements:

- HTTPS required for non-localhost URLs
- Secure client credential generation
- JWT access tokens with proper validation
- Authorization code expiration
- Proper redirect URI validation

## Troubleshooting

### Common Issues

**OAuth endpoints return 404**:
- Ensure `MCP_OAUTH_ENABLED=true`
- Restart the server after configuration changes

**Claude Code connection fails**:
- Check HTTPS configuration for production
- Verify OAuth discovery endpoint responds correctly
- Check server logs for OAuth errors

**Invalid token errors**:
- Verify `MCP_OAUTH_SECRET_KEY` is consistent
- Check token expiration times
- Ensure proper JWT format

### Debug Commands

```bash
# Test OAuth discovery
curl http://localhost:8000/.well-known/oauth-authorization-server/mcp

# Test client registration
curl -X POST http://localhost:8000/oauth/register \
     -H "Content-Type: application/json" \
     -d '{"client_name": "Test Client"}'

# Check server logs
tail -f logs/mcp-memory-service.log | grep -i oauth
```

## API Reference

### Client Registration Request

```json
{
  "client_name": "My Application",
  "redirect_uris": ["https://myapp.com/callback"],
  "grant_types": ["authorization_code"],
  "response_types": ["code"],
  "scope": "read write"
}
```

### Client Registration Response

```json
{
  "client_id": "mcp_client_abc123",
  "client_secret": "secret_xyz789",
  "redirect_uris": ["https://myapp.com/callback"],
  "grant_types": ["authorization_code"],
  "response_types": ["code"],
  "token_endpoint_auth_method": "client_secret_basic"
}
```

### Token Response

```json
{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "scope": "read write"
}
```

## Development

### Running Tests

```bash
# Basic OAuth functionality test
python tests/integration/test_oauth_flow.py

# Full test suite
pytest tests/ -k oauth

# Manual testing with curl
./scripts/test_oauth_flow.sh
```

### Adding New Scopes

1. Update scope definitions in `oauth/models.py`
2. Add scope validation in `oauth/middleware.py`
3. Apply scope requirements to endpoints using `require_scope()`

For more information, see the [OAuth 2.1 specification](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1) and [RFC 7591](https://datatracker.ietf.org/doc/html/rfc7591).
```

--------------------------------------------------------------------------------
/src/mcp_memory_service/storage/factory.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.

"""
Shared storage backend factory for the MCP Memory Service.

This module provides a single, shared factory function for creating storage backends,
eliminating code duplication between the MCP server and web interface initialization.
"""

import logging
from typing import Type

from .base import MemoryStorage

logger = logging.getLogger(__name__)


def _fallback_to_sqlite_vec() -> Type[MemoryStorage]:
    """
    Helper function to fallback to SQLite-vec storage when other backends fail to import.

    Returns:
        SqliteVecMemoryStorage class
    """
    logger.warning("Falling back to SQLite-vec storage")
    from .sqlite_vec import SqliteVecMemoryStorage
    return SqliteVecMemoryStorage


def get_storage_backend_class() -> Type[MemoryStorage]:
    """
    Get storage backend class based on configuration.

    Returns:
        Storage backend class
    """
    from ..config import STORAGE_BACKEND

    backend = STORAGE_BACKEND.lower()

    if backend == "sqlite-vec" or backend == "sqlite_vec":
        from .sqlite_vec import SqliteVecMemoryStorage
        return SqliteVecMemoryStorage
    elif backend == "cloudflare":
        try:
            from .cloudflare import CloudflareStorage
            return CloudflareStorage
        except ImportError as e:
            logger.error(f"Failed to import Cloudflare storage: {e}")
            raise
    elif backend == "hybrid":
        try:
            from .hybrid import HybridMemoryStorage
            return HybridMemoryStorage
        except ImportError as e:
            logger.error(f"Failed to import Hybrid storage: {e}")
            return _fallback_to_sqlite_vec()
    else:
        logger.warning(f"Unknown storage backend '{backend}', defaulting to SQLite-vec")
        from .sqlite_vec import SqliteVecMemoryStorage
        return SqliteVecMemoryStorage


async def create_storage_instance(sqlite_path: str, server_type: str = None) -> MemoryStorage:
    """
    Create and initialize storage backend instance based on configuration.

    Args:
        sqlite_path: Path to SQLite database file (used for SQLite-vec and Hybrid backends)
        server_type: Optional server type identifier ("mcp" or "http") to control hybrid sync ownership

    Returns:
        Initialized storage backend instance
    """
    from ..config import (
        STORAGE_BACKEND, EMBEDDING_MODEL_NAME,
        CLOUDFLARE_API_TOKEN, CLOUDFLARE_ACCOUNT_ID,
        CLOUDFLARE_VECTORIZE_INDEX, CLOUDFLARE_D1_DATABASE_ID,
        CLOUDFLARE_R2_BUCKET, CLOUDFLARE_EMBEDDING_MODEL,
        CLOUDFLARE_LARGE_CONTENT_THRESHOLD, CLOUDFLARE_MAX_RETRIES,
        CLOUDFLARE_BASE_DELAY,
        HYBRID_SYNC_INTERVAL, HYBRID_BATCH_SIZE, HYBRID_SYNC_OWNER
    )

    logger.info(f"Creating storage backend instance (sqlite_path: {sqlite_path}, server_type: {server_type})...")

    # Check if we should override hybrid backend based on sync ownership (v8.27.0+)
    effective_backend = STORAGE_BACKEND
    if STORAGE_BACKEND == 'hybrid' and server_type and HYBRID_SYNC_OWNER != 'both':
        if HYBRID_SYNC_OWNER != server_type:
            logger.info(
                f"Sync ownership configured for '{HYBRID_SYNC_OWNER}' but this is '{server_type}' server. "
                f"Using SQLite-vec storage instead of Hybrid to avoid duplicate sync queues."
            )
            effective_backend = 'sqlite_vec'

    # Get storage class based on effective configuration
    if effective_backend == 'sqlite_vec':
        # Intentional switch to SQLite-vec (not a fallback/error case)
        from .sqlite_vec import SqliteVecMemoryStorage
        StorageClass = SqliteVecMemoryStorage
    else:
        # Use configured backend (hybrid or cloudflare)
        StorageClass = get_storage_backend_class()

    # Create storage instance based on backend type
    if StorageClass.__name__ == "SqliteVecMemoryStorage":
        storage = StorageClass(
            db_path=sqlite_path,
            embedding_model=EMBEDDING_MODEL_NAME
        )
        logger.info(f"Initialized SQLite-vec storage at {sqlite_path}")

    elif StorageClass.__name__ == "CloudflareStorage":
        storage = StorageClass(
            api_token=CLOUDFLARE_API_TOKEN,
            account_id=CLOUDFLARE_ACCOUNT_ID,
            vectorize_index=CLOUDFLARE_VECTORIZE_INDEX,
            d1_database_id=CLOUDFLARE_D1_DATABASE_ID,
            r2_bucket=CLOUDFLARE_R2_BUCKET,
            embedding_model=CLOUDFLARE_EMBEDDING_MODEL,
            large_content_threshold=CLOUDFLARE_LARGE_CONTENT_THRESHOLD,
            max_retries=CLOUDFLARE_MAX_RETRIES,
            base_delay=CLOUDFLARE_BASE_DELAY
        )
        logger.info(f"Initialized Cloudflare storage with vectorize index: {CLOUDFLARE_VECTORIZE_INDEX}")

    elif StorageClass.__name__ == "HybridMemoryStorage":
        # Prepare Cloudflare configuration dict
        cloudflare_config = None
        if all([CLOUDFLARE_API_TOKEN, CLOUDFLARE_ACCOUNT_ID, CLOUDFLARE_VECTORIZE_INDEX, CLOUDFLARE_D1_DATABASE_ID]):
            cloudflare_config = {
                'api_token': CLOUDFLARE_API_TOKEN,
                'account_id': CLOUDFLARE_ACCOUNT_ID,
                'vectorize_index': CLOUDFLARE_VECTORIZE_INDEX,
                'd1_database_id': CLOUDFLARE_D1_DATABASE_ID,
                'r2_bucket': CLOUDFLARE_R2_BUCKET,
                'embedding_model': CLOUDFLARE_EMBEDDING_MODEL,
                'large_content_threshold': CLOUDFLARE_LARGE_CONTENT_THRESHOLD,
                'max_retries': CLOUDFLARE_MAX_RETRIES,
                'base_delay': CLOUDFLARE_BASE_DELAY
            }

        storage = StorageClass(
            sqlite_db_path=sqlite_path,
            embedding_model=EMBEDDING_MODEL_NAME,
            cloudflare_config=cloudflare_config,
            sync_interval=HYBRID_SYNC_INTERVAL,
            batch_size=HYBRID_BATCH_SIZE
        )
        logger.info(f"Initialized hybrid storage with SQLite at {sqlite_path}")

    else:
        # Unknown storage backend - this should not happen as get_storage_backend_class
        # already handles unknown backends by falling back to SQLite-vec
        raise ValueError(f"Unsupported storage backend class: {StorageClass.__name__}")

    # Initialize storage backend
    await storage.initialize()
    logger.info(f"Storage backend {StorageClass.__name__} initialized successfully")

    return storage
```

--------------------------------------------------------------------------------
/tests/unit/test_fastapi_dependencies.py:
--------------------------------------------------------------------------------

```python
"""
Unit tests for FastAPI dependency injection.

These tests verify that the actual dependency injection chain works correctly,
catching issues like import-time default parameter evaluation.

Added to prevent production bugs like v8.12.0 where:
  def get_memory_service(storage: MemoryStorage = get_storage())
was evaluated at import time when _storage was None.
"""

import pytest
import pytest_asyncio
import asyncio
import tempfile
import os
from unittest.mock import MagicMock


@pytest_asyncio.fixture
async def temp_storage():
    """Create a temporary storage for testing."""
    from mcp_memory_service.storage.sqlite_vec import SqliteVecMemoryStorage
    from mcp_memory_service.web.dependencies import set_storage

    with tempfile.TemporaryDirectory() as tmpdir:
        db_path = os.path.join(tmpdir, "test.db")
        storage = SqliteVecMemoryStorage(db_path)
        await storage.initialize()
        set_storage(storage)
        yield storage
        storage.close()


@pytest.mark.asyncio
async def test_get_storage_dependency_callable(temp_storage):
    """Test that get_storage() dependency is callable without errors."""
    from mcp_memory_service.web.dependencies import get_storage

    # Should be callable
    assert callable(get_storage)

    # Should not raise when called
    storage = get_storage()
    assert storage is not None
    assert storage is temp_storage


def test_get_memory_service_dependency_callable():
    """Test that get_memory_service() dependency is callable without errors."""
    from mcp_memory_service.web.dependencies import get_memory_service

    # Should be callable
    assert callable(get_memory_service)

    # Should not raise when called
    try:
        service = get_memory_service()
        assert service is not None
    except Exception as e:
        pytest.fail(f"get_memory_service() raised unexpected exception: {e}")


def test_get_storage_uses_depends_not_default_param():
    """Test that get_storage is used via Depends(), not as default parameter.

    This prevents the v8.12.0 bug where:
      def get_memory_service(storage: MemoryStorage = get_storage())
    was evaluated at import time.
    """
    import inspect
    from mcp_memory_service.web.dependencies import get_memory_service
    from fastapi.params import Depends

    # Get function signature
    sig = inspect.signature(get_memory_service)

    # Check if storage parameter exists
    if 'storage' in sig.parameters:
        storage_param = sig.parameters['storage']

        # If it has a default, it should be Depends(...), not a function call
        if storage_param.default != inspect.Parameter.empty:
            # Default should be a Depends instance, not the result of get_storage()
            # Check the type name since Depends is not a simple type
            assert type(storage_param.default).__name__ == 'Depends', \
                "storage parameter should use Depends(get_storage), not get_storage()"


@pytest.mark.asyncio
async def test_dependency_chain_storage_to_service(temp_storage):
    """Test that the dependency chain from storage → service works."""
    from mcp_memory_service.web.dependencies import get_storage, get_memory_service

    # Get storage
    storage = get_storage()
    assert storage is not None

    # Get service (should use the storage)
    service = get_memory_service()
    assert service is not None

    # Service should have a storage reference
    assert hasattr(service, 'storage')


@pytest.mark.asyncio
async def test_get_storage_returns_singleton(temp_storage):
    """Test that get_storage() returns the same instance (singleton pattern)."""
    from mcp_memory_service.web.dependencies import get_storage

    storage1 = get_storage()
    storage2 = get_storage()

    # Should be the same instance
    assert storage1 is storage2, "get_storage() should return singleton"


def test_get_memory_service_returns_new_instance():
    """Test that get_memory_service() returns new instances (not singleton)."""
    from mcp_memory_service.web.dependencies import get_memory_service

    service1 = get_memory_service()
    service2 = get_memory_service()

    # They use the same storage but are different service instances
    # (This is OK because MemoryService is stateless)
    assert isinstance(service1, type(service2))


def test_dependencies_module_has_required_functions():
    """Test that dependencies module exports required functions."""
    from mcp_memory_service.web import dependencies

    # Core dependency functions
    assert hasattr(dependencies, 'get_storage')
    assert hasattr(dependencies, 'get_memory_service')

    # Should be callable
    assert callable(dependencies.get_storage)
    assert callable(dependencies.get_memory_service)


@pytest.mark.asyncio
async def test_storage_dependency_is_initialized(temp_storage):
    """Test that storage returned by get_storage() is properly initialized."""
    from mcp_memory_service.web.dependencies import get_storage

    storage = get_storage()

    # Check it has expected methods (from base class)
    assert hasattr(storage, 'store')
    assert hasattr(storage, 'get_all_memories')
    assert hasattr(storage, 'get_stats')
    assert hasattr(storage, 'delete')


@pytest.mark.asyncio
async def test_async_dependencies_work(temp_storage):
    """Test that async dependencies work correctly.

    Some storage operations are async, so we need to verify they work.
    """
    from mcp_memory_service.web.dependencies import get_storage

    storage = get_storage()

    # get_stats is async and was the source of issue #191
    stats = await storage.get_stats()
    assert isinstance(stats, dict)
    assert 'total_memories' in stats


def test_dependency_injection_doesnt_fail_on_import():
    """Test that importing dependencies module doesn't cause errors.

    This catches import-time evaluation bugs.
    """
    try:
        # This should not raise
        import mcp_memory_service.web.dependencies
        import mcp_memory_service.web.app

        # App should be created successfully
        from mcp_memory_service.web.app import app
        assert app is not None
    except Exception as e:
        pytest.fail(f"Import-time error in dependencies: {e}")


def test_memory_service_has_required_methods():
    """Test that MemoryService has all required methods."""
    from mcp_memory_service.web.dependencies import get_memory_service

    service = get_memory_service()

    # Core methods from MemoryService class
    required_methods = [
        'store_memory',
        'retrieve_memories',
        'delete_memory',
        'list_memories',  # Not get_all_memories
        'search_by_tag',
        'get_memory_by_hash',
        'health_check',
    ]

    for method in required_methods:
        assert hasattr(service, method), f"MemoryService missing {method}"
        assert callable(getattr(service, method))


if __name__ == "__main__":
    # Allow running tests directly for quick verification
    pytest.main([__file__, "-v"])

```

--------------------------------------------------------------------------------
/docs/guides/chromadb-migration.md:
--------------------------------------------------------------------------------

```markdown
# ChromaDB Migration Guide

> **ChromaDB backend was removed in v8.0.0**. This guide helps you migrate to modern storage backends.

## Quick Migration Path

### Option 1: Hybrid Backend (Recommended)

Best choice for most users - combines fast local storage with cloud synchronization.

```bash
# 1. Backup your ChromaDB data (from chromadb-legacy branch)
git checkout chromadb-legacy
python scripts/migration/migrate_chroma_to_sqlite.py --backup ~/chromadb_backup.json

# 2. Switch to main branch and configure Hybrid backend
git checkout main
export MCP_MEMORY_STORAGE_BACKEND=hybrid

# 3. Configure Cloudflare credentials
export CLOUDFLARE_API_TOKEN="your-token"
export CLOUDFLARE_ACCOUNT_ID="your-account"
export CLOUDFLARE_D1_DATABASE_ID="your-d1-id"
export CLOUDFLARE_VECTORIZE_INDEX="mcp-memory-index"

# 4. Install and verify
python install.py --storage-backend hybrid
python scripts/validation/validate_configuration_complete.py
```

### Option 2: SQLite-vec (Local Only)

For single-device use without cloud synchronization.

```bash
# 1. Backup and migrate
git checkout chromadb-legacy
python scripts/migration/migrate_chroma_to_sqlite.py

# 2. Configure SQLite-vec backend
git checkout main
export MCP_MEMORY_STORAGE_BACKEND=sqlite_vec

# 3. Install
python install.py --storage-backend sqlite_vec
```

### Option 3: Cloudflare (Cloud Only)

For pure cloud storage without local database.

```bash
# 1. Backup ChromaDB data
git checkout chromadb-legacy
python scripts/migration/migrate_chroma_to_sqlite.py --backup ~/chromadb_backup.json

# 2. Switch to Cloudflare backend
git checkout main
export MCP_MEMORY_STORAGE_BACKEND=cloudflare

# 3. Configure Cloudflare credentials
export CLOUDFLARE_API_TOKEN="your-token"
export CLOUDFLARE_ACCOUNT_ID="your-account"
export CLOUDFLARE_D1_DATABASE_ID="your-d1-id"
export CLOUDFLARE_VECTORIZE_INDEX="mcp-memory-index"

# 4. Migrate data to Cloudflare
python scripts/migration/legacy/migrate_chroma_to_sqlite.py
python scripts/sync/sync_memory_backends.py --source sqlite_vec --target cloudflare
```

## Backend Comparison

| Feature | Hybrid ⭐ | SQLite-vec | Cloudflare | ChromaDB (Removed) |
|---------|----------|------------|------------|-------------------|
| **Performance** | 5ms (local) | 5ms | Network | 15ms |
| **Multi-device** | ✅ Yes | ❌ No | ✅ Yes | ❌ No |
| **Offline support** | ✅ Yes | ✅ Yes | ❌ No | ✅ Yes |
| **Cloud backup** | ✅ Auto | ❌ No | ✅ Native | ❌ No |
| **Dependencies** | Light | Minimal | None | Heavy (~2GB) |
| **Setup complexity** | Medium | Easy | Medium | Easy |
| **Status** | **Recommended** | Supported | Supported | **REMOVED** |

## Migration Script Details

### Using the Legacy Migration Script

The ChromaDB migration script is preserved in the legacy branch:

```bash
# From chromadb-legacy branch
python scripts/migration/migrate_chroma_to_sqlite.py [OPTIONS]

Options:
  --source PATH       Path to ChromaDB data (default: CHROMA_PATH from config)
  --target PATH       Path for SQLite database (default: SQLITE_VEC_PATH)
  --backup PATH       Create JSON backup of ChromaDB data
  --validate          Validate migration integrity
  --dry-run           Show what would be migrated without making changes
```

### Manual Migration Steps

If you prefer manual control:

1. **Export from ChromaDB**:
   ```bash
   git checkout chromadb-legacy
   python -c "
   from mcp_memory_service.storage.chroma import ChromaMemoryStorage
   import json
   storage = ChromaMemoryStorage(path='./chroma_db')
   memories = storage.get_all_memories()
   with open('export.json', 'w') as f:
       json.dump([m.to_dict() for m in memories], f)
   "
   ```

2. **Import to new backend**:
   ```bash
   git checkout main
   python -c "
   from mcp_memory_service.storage.sqlite_vec import SqliteVecMemoryStorage
   import json
   storage = SqliteVecMemoryStorage(db_path='./memory.db')
   await storage.initialize()
   with open('export.json') as f:
       memories = json.load(f)
   for mem in memories:
       await storage.store(Memory.from_dict(mem))
   "
   ```

## Data Validation

After migration, verify your data:

```bash
# Check memory count
python -c "
from mcp_memory_service.storage.factory import create_storage_instance
storage = await create_storage_instance('./memory.db')
count = len(await storage.get_all_memories())
print(f'Migrated {count} memories')
"

# Compare with backup
python scripts/validation/validate_migration.py \
    --source ~/chromadb_backup.json \
    --target ./memory.db
```

## Troubleshooting

### Issue: Migration script not found

**Solution**: The migration script is only available on the `chromadb-legacy` branch:
```bash
git checkout chromadb-legacy
python scripts/migration/migrate_chroma_to_sqlite.py
```

### Issue: Import errors for ChromaMemoryStorage

**Solution**: You must be on the `chromadb-legacy` branch to access ChromaDB code:
```bash
git checkout chromadb-legacy  # ChromaDB code available
git checkout main             # ChromaDB removed (v8.0.0+)
```

### Issue: "ChromaDB not installed" error

**Solution**: Install chromadb on the legacy branch:
```bash
git checkout chromadb-legacy
pip install chromadb>=0.5.0 sentence-transformers>=2.2.2
```

### Issue: Memory timestamps lost during migration

**Solution**: Use `--preserve-timestamps` flag:
```bash
python scripts/migration/migrate_chroma_to_sqlite.py --preserve-timestamps
```

### Issue: Large ChromaDB database migration is slow

**Solution**: Use batch mode for faster migration:
```bash
python scripts/migration/migrate_chroma_to_sqlite.py --batch-size 100
```

## Rollback Plan

If you need to rollback to ChromaDB (not recommended):

1. **Stay on v7.x releases** - Do not upgrade to v8.0.0
2. **Use chromadb-legacy branch** for reference
3. **Restore from backup**:
   ```bash
   git checkout chromadb-legacy
   python scripts/migration/restore_from_backup.py ~/chromadb_backup.json
   ```

## Post-Migration Checklist

- [ ] Backup completed successfully
- [ ] Migration script ran without errors
- [ ] Memory count matches between old and new backend
- [ ] Sample queries return expected results
- [ ] Configuration updated (`MCP_MEMORY_STORAGE_BACKEND`)
- [ ] Legacy ChromaDB data directory backed up
- [ ] Validation script passes
- [ ] Application tests pass
- [ ] Claude Desktop/Code integration works

## Support

- **Migration issues**: See [Issue #148](https://github.com/doobidoo/mcp-memory-service/issues/148)
- **Legacy branch**: [chromadb-legacy](https://github.com/doobidoo/mcp-memory-service/tree/chromadb-legacy)
- **Backend setup**: See [STORAGE_BACKENDS.md](./STORAGE_BACKENDS.md)

## Why Was ChromaDB Removed?

- **Performance**: 3x slower than SQLite-vec (15ms vs 5ms)
- **Dependencies**: Required ~2GB PyTorch download
- **Complexity**: 2,841 lines of code removed
- **Better alternatives**: Hybrid backend provides better performance with cloud sync
- **Maintenance**: Reduced long-term maintenance burden

The removal improves the project's maintainability while offering better performance through modern alternatives.

```

--------------------------------------------------------------------------------
/docs/development/code-quality/phase-2a-handle-get-prompt.md:
--------------------------------------------------------------------------------

```markdown
# Refactoring: handle_get_prompt() - Phase 2, Function #5

## Summary
Refactored `server.py::handle_get_prompt()` to reduce cyclomatic complexity and improve maintainability through Extract Method pattern.

**Metrics:**
- **Original Complexity:** 33
- **Refactored Main Function:** Complexity 6 (82% reduction)
- **Original Lines:** 208
- **Refactored Main Function:** 41 lines
- **Helper Functions Created:** 5

## Refactoring Strategy: Extract Method Pattern

The function contained a long if/elif/else chain handling 5 different prompt types. Each prompt type required 25-40 lines of specialized logic with high nesting and branching.

### Helper Functions Extracted

#### 1. `_prompt_memory_review()` - CC: 5
**Purpose:** Handle "memory_review" prompt type
**Responsibilities:**
- Parse time_period and focus_area arguments
- Retrieve memories from specified time period
- Format memories as prompt text with tags

**Location:** Lines ~1320-1347
**Input:** arguments dict
**Output:** List of PromptMessage objects

---

#### 2. `_prompt_memory_analysis()` - CC: 8
**Purpose:** Handle "memory_analysis" prompt type  
**Responsibilities:**
- Parse tags and time_range arguments
- Retrieve relevant memories
- Analyze patterns (tag counts, memory types)
- Build analysis report text

**Location:** Lines ~1349-1388
**Input:** arguments dict
**Output:** List of PromptMessage objects
**Complexity Source:** Double-nested loops for pattern analysis (2 for loops)

---

#### 3. `_prompt_knowledge_export()` - CC: 8
**Purpose:** Handle "knowledge_export" prompt type
**Responsibilities:**
- Parse format_type and filter criteria
- Retrieve memories based on filter
- Format export in JSON/Markdown/Text based on format_type
- Build export text

**Location:** Lines ~1390-1428
**Input:** arguments dict
**Output:** List of PromptMessage objects
**Complexity Source:** Multiple format branches (if/elif/else)

---

#### 4. `_prompt_memory_cleanup()` - CC: 6
**Purpose:** Handle "memory_cleanup" prompt type
**Responsibilities:**
- Parse cleanup parameters
- Find duplicate memories
- Build cleanup report
- Provide recommendations

**Location:** Lines ~1430-1458
**Input:** arguments dict
**Output:** List of PromptMessage objects
**Complexity Source:** Nested loop for duplicate detection

---

#### 5. `_prompt_learning_session()` - CC: 5
**Purpose:** Handle "learning_session" prompt type
**Responsibilities:**
- Parse topic, key_points, and questions
- Create structured learning note
- Store as memory
- Return formatted response

**Location:** Lines ~1460-1494
**Input:** arguments dict
**Output:** List of PromptMessage objects

---

## Refactored `handle_get_prompt()` Function - CC: 6

**New Structure:**
```python
async def handle_get_prompt(self, name: str, arguments: dict):
    await self._ensure_storage_initialized()
    
    # Simple dispatch to specialized handlers
    if name == "memory_review":
        messages = await self._prompt_memory_review(arguments)
    elif name == "memory_analysis":
        messages = await self._prompt_memory_analysis(arguments)
    # ... etc
    else:
        messages = [unknown_prompt_message]
    
    return GetPromptResult(description=..., messages=messages)
```

**Lines:** 41 (vs 208 original)
**Control Flow:** Reduced from 33 branches to 6 (if/elif chain only)

## Benefits

### Code Quality
- ✅ **Single Responsibility:** Each function handles one prompt type
- ✅ **Testability:** Each prompt type can be unit tested independently
- ✅ **Readability:** Main function is now a simple dispatcher
- ✅ **Maintainability:** Changes to one prompt type isolated to its handler
- ✅ **Extensibility:** Adding new prompt types requires just another elif

### Complexity Distribution
```
handle_get_prompt:         CC 6   (dispatcher)
_prompt_memory_review:     CC 5   (simple retrieval + format)
_prompt_memory_analysis:   CC 8   (pattern analysis)
_prompt_knowledge_export:  CC 8   (multiple format branches)
_prompt_memory_cleanup:    CC 6   (duplicate detection)
_prompt_learning_session:  CC 5   (create + store)
```

**Total distributed complexity:** 38 (vs 33 monolithic)
**Max function complexity:** 8 (vs 33 monolithic) - 75% reduction in peak complexity

### Maintainability Improvements
- Prompt handlers are now 27-39 lines each (vs 208 for entire function)
- Clear naming convention (`_prompt_<type>`) makes intent obvious
- Easier to locate specific prompt logic
- Reduces cognitive load when reading main function
- New developers can understand each handler independently

## Backward Compatibility

✅ **Fully compatible** - No changes to:
- Function signature: `handle_get_prompt(name, arguments) -> GetPromptResult`
- Return values: Same GetPromptResult structure
- Argument processing: Same argument parsing
- All prompt types: Same behavior

## Testing Recommendations

### Unit Tests
- `test_prompt_memory_review()` - Test memory retrieval + formatting
- `test_prompt_memory_analysis()` - Test pattern analysis logic
- `test_prompt_knowledge_export()` - Test each format (JSON/MD/text)
- `test_prompt_memory_cleanup()` - Test duplicate detection
- `test_prompt_learning_session()` - Test storage logic

### Integration Tests  
- Test all 5 prompt types through handle_get_prompt()
- Verify error handling for unknown prompts
- Test with various argument combinations

## Related Issues

- **Issue #246:** Code Quality Phase 2 - Reduce Function Complexity
- **Phase 2 Progress:** 4/27 high-risk functions completed
  - ✅ `install.py::main()` - Complexity 62 → ~8
  - ✅ `sqlite_vec.py::initialize()` - Complexity 38 → Reduced
  - ✅ `install_package()` - Complexity 33 → 7
  - ✅ `handle_get_prompt()` - Complexity 33 → 6 (THIS REFACTORING)

## Files Modified

- `src/mcp_memory_service/server.py`: Refactored `handle_get_prompt()` with 5 helper methods

## Git Commit

Use semantic commit message:
```
refactor: reduce handle_get_prompt() complexity from 33 to 6 (82% reduction)

Extract prompt type handlers:
- _prompt_memory_review (CC 5) - Memory retrieval + formatting
- _prompt_memory_analysis (CC 8) - Pattern analysis
- _prompt_knowledge_export (CC 8) - Multi-format export
- _prompt_memory_cleanup (CC 6) - Duplicate detection
- _prompt_learning_session (CC 5) - Learning note creation

Main dispatcher now 41 lines (vs 208 original) with CC 6.
All handlers individually testable and maintainable.
Addresses issue #246 Phase 2, function #5 in refactoring plan.
```

## Code Review Checklist

- [x] Code compiles without errors
- [x] All handlers extract correctly
- [x] Dispatcher logic correct
- [x] No changes to external API
- [x] Backward compatible
- [x] Complexity reduced
- [ ] All tests pass (manual verification needed)
- [ ] Integration tested

## Future Improvements

1. **Prompt Registry:** Create a dictionary-based prompt registry for even simpler dispatch
2. **Configuration:** Make prompt definitions configurable
3. **Validation:** Add argument schema validation for each prompt type
4. **Documentation:** Auto-generate prompt documentation from handler implementations

```

--------------------------------------------------------------------------------
/tests/bridge/mock_responses.js:
--------------------------------------------------------------------------------

```javascript
/**
 * Mock Server Responses for Testing
 * 
 * These responses match the ACTUAL behavior of the MCP Memory Service API,
 * not what we might assume or hope it returns.
 */

const mockResponses = {
    // Health endpoint responses
    health: {
        healthy: {
            status: 200, // NOT 204 or other codes
            body: {
                status: 'healthy',
                version: '6.6.1',
                timestamp: '2025-08-24T12:00:00Z',
                uptime_seconds: 3600,
                storage_type: 'sqlite_vec',
                statistics: {
                    total_memories: 100,
                    total_tags: 25
                }
            }
        },
        unhealthy: {
            status: 503,
            body: {
                status: 'unhealthy',
                error: 'Database connection failed'
            }
        }
    },
    
    // Memory storage responses - CRITICAL: Server returns 200, not 201!
    memories: {
        createSuccess: {
            status: 200, // ACTUAL: Returns 200, not 201 for creation!
            body: {
                success: true, // Key field for determining actual success
                message: 'Memory stored successfully',
                content_hash: 'abc123def456',
                memory: {
                    content: 'Test memory content',
                    content_hash: 'abc123def456',
                    tags: ['test', 'source:test-client'],
                    memory_type: 'note',
                    metadata: {
                        hostname: 'test-client'
                    },
                    created_at: 1756054456.123,
                    created_at_iso: '2025-08-24T12:00:00.123Z',
                    updated_at: 1756054456.123,
                    updated_at_iso: '2025-08-24T12:00:00.123Z'
                }
            }
        },
        duplicate: {
            status: 200, // SAME status code as success!
            body: {
                success: false, // This field determines it's a duplicate
                message: 'Duplicate content detected',
                content_hash: 'abc123def456',
                memory: null
            }
        },
        invalidRequest: {
            status: 400,
            body: {
                detail: 'Invalid request: content is required'
            }
        },
        unauthorized: {
            status: 401,
            body: {
                detail: 'Invalid API key'
            }
        },
        serverError: {
            status: 500,
            body: {
                detail: 'Internal server error'
            }
        }
    },
    
    // Memory retrieval/search responses
    search: {
        withResults: {
            status: 200,
            body: {
                results: [
                    {
                        memory: {
                            content: 'Matching memory content',
                            content_hash: 'hash1',
                            tags: ['test', 'search'],
                            memory_type: 'note',
                            created_at_iso: '2025-08-24T11:00:00Z',
                            metadata: {}
                        },
                        relevance_score: 0.95
                    },
                    {
                        memory: {
                            content: 'Another matching memory',
                            content_hash: 'hash2',
                            tags: ['test'],
                            memory_type: 'reference',
                            created_at_iso: '2025-08-24T10:00:00Z',
                            metadata: {}
                        },
                        relevance_score: 0.87
                    }
                ]
            }
        },
        empty: {
            status: 200,
            body: {
                results: []
            }
        }
    },
    
    // Tag search responses
    tagSearch: {
        withResults: {
            status: 200,
            body: {
                memories: [
                    {
                        content: 'Memory with specific tag',
                        content_hash: 'tag_hash1',
                        tags: ['specific-tag', 'other-tag'],
                        memory_type: 'note',
                        created_at_iso: '2025-08-24T09:00:00Z'
                    }
                ]
            }
        },
        empty: {
            status: 200,
            body: {
                memories: []
            }
        }
    },
    
    // Delete memory responses
    deleteMemory: {
        success: {
            status: 200,
            body: {
                success: true,
                message: 'Memory deleted successfully'
            }
        },
        notFound: {
            status: 404,
            body: {
                detail: 'Memory not found'
            }
        }
    },
    
    // Edge cases and error conditions
    edgeCases: {
        // When the /api path is missing (404 because endpoint wrong)
        missingApiPath: {
            status: 404,
            body: {
                detail: 'Not Found'
            }
        },
        // Network timeout
        timeout: {
            error: new Error('ETIMEDOUT')
        },
        // Connection refused
        connectionRefused: {
            error: new Error('ECONNREFUSED')
        },
        // Invalid JSON response
        invalidJson: {
            status: 200,
            body: 'This is not JSON', // String instead of object
            raw: true
        },
        // HTML error page instead of JSON
        htmlError: {
            status: 500,
            body: '<html><body>500 Internal Server Error</body></html>',
            raw: true,
            contentType: 'text/html'
        }
    }
};

/**
 * Helper function to create a mock HTTP response object
 */
function createMockResponse(mockData) {
    if (mockData.error) {
        throw mockData.error;
    }
    
    return {
        statusCode: mockData.status,
        headers: {
            'content-type': mockData.contentType || 'application/json'
        },
        on: (event, callback) => {
            if (event === 'data') {
                const data = mockData.raw ? 
                    mockData.body : 
                    JSON.stringify(mockData.body);
                callback(Buffer.from(data));
            } else if (event === 'end') {
                callback();
            }
        }
    };
}

/**
 * Helper to create a mock request object
 */
function createMockRequest() {
    const req = {
        on: (event, callback) => {
            if (event === 'error') {
                // Store error handler
                req.errorHandler = callback;
            } else if (event === 'timeout') {
                req.timeoutHandler = callback;
            }
        },
        write: () => {},
        end: () => {},
        destroy: () => {},
        setTimeout: () => {}
    };
    return req;
}

module.exports = {
    mockResponses,
    createMockResponse,
    createMockRequest
};
```

--------------------------------------------------------------------------------
/scripts/server/run_memory_server.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.

"""
Direct runner for MCP Memory Service.
This script directly imports and runs the memory server without going through the installation process.
"""
import os
import sys
import importlib.util
import importlib.machinery
import traceback

# Disable sitecustomize.py and other import hooks to prevent recursion issues
os.environ["PYTHONNOUSERSITE"] = "1"  # Disable user site-packages
os.environ["PYTHONPATH"] = ""  # Clear PYTHONPATH

# Set environment variables to prevent pip from installing dependencies
os.environ["PIP_NO_DEPENDENCIES"] = "1"
os.environ["PIP_NO_INSTALL"] = "1"

# Set environment variables for better cross-platform compatibility
os.environ["PYTORCH_ENABLE_MPS_FALLBACK"] = "1"

# For Windows with limited GPU memory, use smaller chunks
os.environ["PYTORCH_CUDA_ALLOC_CONF"] = "max_split_size_mb:128"

# Set ChromaDB path if provided via environment variables
if "MCP_MEMORY_CHROMA_PATH" in os.environ:
    print(f"Using ChromaDB path: {os.environ['MCP_MEMORY_CHROMA_PATH']}", file=sys.stderr, flush=True)

# Set backups path if provided via environment variables
if "MCP_MEMORY_BACKUPS_PATH" in os.environ:
    print(f"Using backups path: {os.environ['MCP_MEMORY_BACKUPS_PATH']}", file=sys.stderr, flush=True)

def print_info(text):
    """Print formatted info text."""
    print(f"[INFO] {text}", file=sys.stderr, flush=True)

def print_error(text):
    """Print formatted error text."""
    print(f"[ERROR] {text}", file=sys.stderr, flush=True)

def print_success(text):
    """Print formatted success text."""
    print(f"[SUCCESS] {text}", file=sys.stderr, flush=True)

def print_warning(text):
    """Print formatted warning text."""
    print(f"[WARNING] {text}", file=sys.stderr, flush=True)

def run_memory_server():
    """Run the MCP Memory Service directly."""
    print_info("Starting MCP Memory Service")
    
    # Save original sys.path and meta_path
    original_sys_path = sys.path.copy()
    original_meta_path = sys.meta_path
    
    # Temporarily disable import hooks
    sys.meta_path = [finder for finder in sys.meta_path
                    if not hasattr(finder, 'find_spec') or
                    not hasattr(finder, 'blocked_packages')]
    
    try:
        # Get the directory of this script
        script_dir = os.path.dirname(os.path.abspath(__file__))
        # Go up two directories from scripts/server/ to reach the project root
        project_root = os.path.dirname(os.path.dirname(script_dir))

        # Add src directory to path if it exists (prioritize local development)
        src_dir = os.path.join(project_root, "src")
        if os.path.exists(src_dir):
            print_info(f"Adding {src_dir} to sys.path (prioritized for development)")
            # Remove any existing mcp_memory_service from sys.modules to avoid conflicts
            modules_to_remove = [key for key in sys.modules.keys() if key.startswith('mcp_memory_service')]
            for module in modules_to_remove:
                print_info(f"Removing conflicting module: {module}")
                del sys.modules[module]

            # Insert src at the very beginning to override any installed packages
            if src_dir in sys.path:
                sys.path.remove(src_dir)
            sys.path.insert(0, src_dir)
        else:
            # Add site-packages to sys.path only if src doesn't exist
            site_packages = os.path.join(sys.prefix, 'Lib', 'site-packages')
            if site_packages not in sys.path:
                sys.path.insert(0, site_packages)
        
        # Try direct import from src directory
        server_path = os.path.join(src_dir, "mcp_memory_service", "server.py")
        if os.path.exists(server_path):
            print_info(f"Found server module at {server_path}")
            
            # Use importlib to load the module directly from the file
            module_name = "mcp_memory_service.server"
            spec = importlib.util.spec_from_file_location(module_name, server_path)
            if spec is None:
                print_error(f"Could not create spec from file: {server_path}")
                sys.exit(1)
                
            server = importlib.util.module_from_spec(spec)
            sys.modules[module_name] = server  # Add to sys.modules to avoid import issues
            spec.loader.exec_module(server)
            
            print_success("Successfully imported mcp_memory_service.server from file")
        else:
            # Try to import using importlib
            print_info("Attempting to import mcp_memory_service.server using importlib")
            
            # First try to find the module in site-packages
            server_spec = importlib.machinery.PathFinder.find_spec('mcp_memory_service.server', [site_packages])
            
            # If not found, try to find it in src directory
            if server_spec is None and os.path.exists(src_dir):
                server_spec = importlib.machinery.PathFinder.find_spec('mcp_memory_service.server', [src_dir])
            
            if server_spec is None:
                print_error("Could not find mcp_memory_service.server module spec")
                sys.exit(1)
            
            # Load the server module
            server = importlib.util.module_from_spec(server_spec)
            server_spec.loader.exec_module(server)
            
            print_success("Successfully imported mcp_memory_service.server")
        
        # Run the memory server with error handling
        try:
            print_info("Calling mcp_memory_service.server.main()")
            server.main()
        except Exception as e:
            print_error(f"Error running memory server: {e}")
            traceback.print_exc(file=sys.stderr)
            sys.exit(1)
    except ImportError as e:
        print_error(f"Failed to import mcp_memory_service.server: {e}")
        traceback.print_exc(file=sys.stderr)
        sys.exit(1)
    except Exception as e:
        print_error(f"Error setting up memory server: {e}")
        traceback.print_exc(file=sys.stderr)
        sys.exit(1)
    finally:
        # Restore original sys.path and meta_path
        sys.path = original_sys_path
        sys.meta_path = original_meta_path

if __name__ == "__main__":
    try:
        run_memory_server()
    except KeyboardInterrupt:
        print_info("Script interrupted by user")
        sys.exit(0)
    except Exception as e:
        print_error(f"Unhandled exception: {e}")
        traceback.print_exc(file=sys.stderr)
        sys.exit(1)
```

--------------------------------------------------------------------------------
/docs/development/code-quality/phase-2b-session-summary.md:
--------------------------------------------------------------------------------

```markdown
# Phase 2b Session Summary

## Session Goal
Reduce code duplication from 4.9% to <3% by consolidating remaining 5 clone groups.

## Work Completed

### Group 3: Document Chunk Processing ✅ COMPLETED
**Status**: Successfully consolidated and tested
**Impact**: ~25-40 lines eliminated

#### What Was Done
- Extracted `_process_and_store_chunk()` helper function in `document_processing.py`
- Consolidated 3 duplicated chunk-to-memory processing blocks across:
  - `src/mcp_memory_service/cli/ingestion.py:275-299` (25 lines)
  - `src/mcp_memory_service/server.py:3857-3881` (25 lines)
  - `src/mcp_memory_service/web/api/documents.py:526-556` (31 lines)

#### Benefits
- Reduced code duplication in document processing pipeline
- Improved maintainability of chunk handling logic
- Consistent error handling across entry points
- Support for extra metadata, memory types, and context tags

#### Testing
- ✅ All document processing tests pass (26 tests)
- ✅ All ingestion tests pass (loader tests, chunking, etc.)
- ✅ No regression in memory service functionality
- ✅ Syntax validation passes

#### Commit
```
commit b3ac4a2
refactor: Phase 2b-1 - Consolidate chunk processing logic (Group 3)
- Extract _process_and_store_chunk() helper function
- Consolidate 3 duplicated blocks (81 lines total)
- Reduced code duplication and improved maintainability
```

---

## Remaining Groups Analysis

### Group 0: Test/Script Duplication ⏭️ DEFERRED
**Files**: Test helper patterns across multiple test scripts
- `claude-hooks/install_hooks.py:180-203` (24 lines)
- `scripts/testing/test_memory_simple.py:91-102` (12 lines)
- `scripts/testing/test_search_api.py:79-96` (18 lines)

**Assessment**: These are request/response handling patterns in test scripts with different error reporting needs. Low priority as they don't affect production code.

**Why Deferred**:
- Test/script files have different error handling conventions
- Would require creating shared test utilities module
- Lower impact on production code quality
- Risk of breaking test-specific error reporting

---

### Group 1: Error Handling Pattern (Install Utilities) ⏭️ DEFERRED
**Files**: Version checking and error fallback patterns
- `scripts/installation/install.py:68-77` (10 lines)
- `scripts/installation/install.py:839-849` (11 lines)
- `src/mcp_memory_service/utils/port_detection.py:70-84` (15 lines)

**Assessment**: Complex error handling patterns with different exception types and fallback logic. Would require careful refactoring to maintain semantic meaning.

**Why Deferred**:
- Spans installation scripts and core utilities
- Different error recovery semantics for each instance
- Requires deep understanding of fallback requirements
- Risk of breaking installation process

---

### Group 2: Migration/Initialization Output ⏭️ DEFERRED
**Files**: Status message and initialization output patterns
- `scripts/installation/install.py:1617-1628` (12 lines)
- `scripts/migration/migrate_v5_enhanced.py:591-601` (11 lines)
- `src/mcp_memory_service/server.py:3948-3957` (10 lines)

**Assessment**: Output/logging patterns for user-facing status messages. These are context-specific and serve different purposes (CLI output, migration reporting, diagnostics).

**Why Deferred**:
- Different output contexts (installation, migration, diagnostics)
- User-facing messages require careful wording
- Would need extensive testing across all contexts
- Risk of losing important semantic distinctions

---

### Group 4: Storage Health Validation (High-Risk) ⏭️ DEFERRED
**Files**: Storage backend validation logic
- `src/mcp_memory_service/server.py:3369-3428` (60 lines)
- `src/mcp_memory_service/server.py:3380-3428` (49 lines overlap)
- `src/mcp_memory_service/server.py:3391-3428` (38 lines overlap)

**Assessment**: Complex nested validation logic for different storage backends (SQLite-vec, Cloudflare, Hybrid). The overlapping line ranges indicate deeply nested if-else branches with error handling at multiple levels.

**Why High Risk for Refactoring**:
1. **Nested Validation Logic**: Each storage type has cascading conditional checks with specific error messages
2. **State-Dependent Behavior**: Validation depends on storage initialization state
3. **Multiple Error Paths**: Different error recovery strategies for each backend
4. **Performance Critical**: Health check is used during startup and monitoring
5. **Integration Risk**: Changes could affect server startup timing and reliability
6. **Testing Complexity**: Would need comprehensive testing of all three storage backends plus all error conditions

**Refactoring Challenges**:
- Extracting a helper would require handling branching logic carefully
- Each backend has unique validation requirements
- Error messages are specific to help debugging storage issues
- Any regression could prevent server startup

**Recommendation**: Leave as-is. The code is well-documented and the business logic is appropriately matched to the domain complexity.

---

## Current Duplication Status

**Estimated After Group 3**: 4.5-4.7% (down from 4.9%)
- Eliminated ~40-50 effective lines through consolidation
- Created reusable helper for future document processing use cases

**Path to <3%**:
To reach <3% would require consolidating Groups 1, 2, and 4:
- Group 1: 36 total lines, medium risk
- Group 2: 33 total lines, medium risk  
- Group 4: 147 total lines, **HIGH RISK**

Total estimated consolidation: ~215 lines from remaining groups
- But Groups 1 & 2 have lower consolidation benefit due to semantic differences
- Group 4 has high refactoring risk relative to benefit

---

## Recommendations for Future Work

### Phase 3 Strategy
If further duplication reduction is needed, prioritize in this order:

1. **Group 1 (Medium Priority)**
   - Extract error handling helpers for version/configuration checks
   - Create `utils/installation_helpers.py` for shared patterns
   - Estimated savings: ~25 effective lines

2. **Group 2 (Medium Priority)**
   - Create output formatting helper for status messages
   - Consolidate user-facing message templates
   - Estimated savings: ~20 effective lines

3. **Group 4 (Low Priority, High Risk)**
   - Only if duplication metric becomes critical
   - Requires comprehensive refactoring with full test suite coverage
   - Consider extracting per-backend validators as separate methods
   - Estimated savings: ~80-100 effective lines, but high regression risk

### Testing Requirements for Future Work
- Full integration tests for Groups 1 & 2
- Multi-backend health check tests for Group 4
- Installation flow tests with fallback scenarios
- Migration validation under various database states

---

## Conclusion

Successfully completed Group 3 consolidation, creating a reusable helper function for document chunk processing. This represents a meaningful reduction in duplication while maintaining code clarity and maintainability.

The remaining 4 groups have lower priority or higher risk profiles:
- Groups 0, 1, 2 are lower impact (test/utility code)
- Group 4 is high risk with nested logic across multiple backends

**Current Achievement**: ~25-40 lines consolidated with 100% test pass rate and no regressions.

```

--------------------------------------------------------------------------------
/scripts/sync/export_memories.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.

"""
Export memories from SQLite-vec database to JSON format.

This script exports all memories from a local SQLite-vec database,
preserving timestamps, metadata, and adding source tracking for
multi-machine synchronization.
"""

import asyncio
import sys
import logging
import argparse
import platform
from pathlib import Path
from datetime import datetime

# Add project src to path
project_root = Path(__file__).parent.parent.parent
sys.path.insert(0, str(project_root / "src"))

from mcp_memory_service.storage.sqlite_vec import SqliteVecMemoryStorage
from mcp_memory_service.sync.exporter import MemoryExporter
from mcp_memory_service.config import SQLITE_VEC_PATH, STORAGE_BACKEND

# Configure logging
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)


def get_default_db_path() -> Path:
    """Get the default database path for this platform."""
    if STORAGE_BACKEND == 'sqlite_vec' and SQLITE_VEC_PATH:
        return Path(SQLITE_VEC_PATH)
    else:
        # Fallback to BASE_DIR if not using sqlite_vec backend
        from mcp_memory_service.config import BASE_DIR
        return Path(BASE_DIR) / "sqlite_vec.db"


def get_default_output_filename() -> str:
    """Generate a default output filename based on machine and timestamp."""
    machine_name = platform.node().lower().replace(' ', '-')
    timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
    return f"{machine_name}_memories_export_{timestamp}.json"


async def export_memories(
    db_path: Path,
    output_file: Path,
    include_embeddings: bool = False,
    filter_tags: list = None
):
    """Export memories from database to JSON file."""
    logger.info(f"Starting memory export from {db_path}")
    
    # Check if database exists
    if not db_path.exists():
        logger.error(f"Database not found at {db_path}")
        logger.info("Available storage locations:")
        logger.info(f"  Default: {get_default_db_path()}")
        return False
    
    try:
        # Initialize storage
        logger.info("Initializing SQLite-vec storage...")
        storage = SqliteVecMemoryStorage(str(db_path))
        await storage.initialize()
        
        # Create exporter
        exporter = MemoryExporter(storage)
        
        # Show summary first
        logger.info("Analyzing database...")
        summary = await exporter.export_summary()
        
        logger.info(f"Database analysis:")
        logger.info(f"  Total memories: {summary['total_memories']}")
        logger.info(f"  Machine: {summary['machine_name']}")
        logger.info(f"  Date range: {summary['date_range']['earliest']} to {summary['date_range']['latest']}")
        logger.info(f"  Memory types: {summary['memory_types']}")
        logger.info(f"  Top tags: {list(summary['tag_counts'].items())[:5]}")
        logger.info(f"  Estimated size: {summary['estimated_json_size_mb']:.1f} MB")
        
        # Perform export
        logger.info(f"Exporting to {output_file}...")
        result = await exporter.export_to_json(
            output_file=output_file,
            include_embeddings=include_embeddings,
            filter_tags=filter_tags
        )
        
        if result["success"]:
            logger.info("Export completed successfully!")
            logger.info(f"  Exported: {result['exported_count']} memories")
            logger.info(f"  Output file: {result['output_file']}")
            logger.info(f"  File size: {result['file_size_bytes'] / 1024 / 1024:.2f} MB")
            logger.info(f"  Source machine: {result['source_machine']}")
            
            # Show next steps
            logger.info("")
            logger.info("Next steps:")
            logger.info("1. Transfer this JSON file to your central server")
            logger.info("2. Run import_memories.py on the central server")
            logger.info("3. Set up Litestream for ongoing synchronization")
            
            return True
        else:
            logger.error("Export failed")
            return False
            
    except Exception as e:
        logger.error(f"Export failed: {str(e)}")
        return False


async def main():
    """Main function."""
    parser = argparse.ArgumentParser(
        description="Export memories from SQLite-vec database to JSON",
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog="""
Examples:
  # Export all memories with default settings
  python export_memories.py
  
  # Export from specific database
  python export_memories.py --db-path /path/to/sqlite_vec.db
  
  # Export to specific file
  python export_memories.py --output my_export.json
  
  # Export only memories with specific tags
  python export_memories.py --filter-tags claude-code,architecture
  
  # Include embedding vectors (increases file size significantly)
  python export_memories.py --include-embeddings
        """
    )
    
    parser.add_argument(
        "--db-path",
        type=Path,
        default=get_default_db_path(),
        help=f"Path to SQLite-vec database (default: {get_default_db_path()})"
    )
    
    parser.add_argument(
        "--output",
        type=Path,
        default=get_default_output_filename(),
        help=f"Output JSON file (default: {get_default_output_filename()})"
    )
    
    parser.add_argument(
        "--include-embeddings",
        action="store_true",
        help="Include embedding vectors in export (increases file size)"
    )
    
    parser.add_argument(
        "--filter-tags",
        nargs="*",
        help="Only export memories with these tags"
    )
    
    parser.add_argument(
        "--verbose",
        action="store_true",
        help="Enable verbose logging"
    )
    
    args = parser.parse_args()
    
    # Set logging level
    if args.verbose:
        logging.getLogger().setLevel(logging.DEBUG)
    
    # Show configuration
    logger.info("Memory Export Configuration:")
    logger.info(f"  Database: {args.db_path}")
    logger.info(f"  Output: {args.output}")
    logger.info(f"  Include embeddings: {args.include_embeddings}")
    logger.info(f"  Filter tags: {args.filter_tags}")
    logger.info(f"  Platform: {platform.system()} {platform.release()}")
    logger.info("")
    
    # Run export
    success = await export_memories(
        db_path=args.db_path,
        output_file=args.output,
        include_embeddings=args.include_embeddings,
        filter_tags=args.filter_tags
    )
    
    sys.exit(0 if success else 1)


if __name__ == "__main__":
    asyncio.run(main())
```

--------------------------------------------------------------------------------
/docs/CLAUDE_CODE_QUICK_REFERENCE.md:
--------------------------------------------------------------------------------

```markdown
# Claude Code Quick Reference for MCP Memory Service

**One-page cheat sheet for efficient development with Claude Code**

---

## 🎯 Essential Keybindings

| Key | Action | Use Case |
|-----|--------|----------|
| `Shift+Tab` | Auto-accept edits | Fast iteration on suggested changes |
| `Esc` | Cancel operation | Stop unwanted actions |
| `Ctrl+R` | Verbose output | Debug when things go wrong |
| `#` | Create memory | Store important decisions |
| `@` | Add to context | Include files/dirs (`@src/`, `@tests/`) |
| `!` | Bash mode | Quick shell commands |

---

## 🚀 Common Tasks

### Memory Operations

```bash
# Store information
/memory-store "Hybrid backend uses SQLite primary + Cloudflare secondary"

# Retrieve information
/memory-recall "how to configure Cloudflare backend"

# Check service health
/memory-health
```

### Development Workflow

```bash
# 1. Start with context
@src/mcp_memory_service/storage/
@tests/test_storage.py

# 2. Make changes incrementally
# Accept suggestions with Shift+Tab

# 3. Test immediately
pytest tests/test_storage.py -v

# 4. Document decisions
/memory-store "Changed X because Y"
```

### Backend Configuration

```bash
# Check current backend
python scripts/server/check_http_server.py -v

# Validate configuration
python scripts/validation/validate_configuration_complete.py

# Diagnose issues
python scripts/validation/diagnose_backend_config.py
```

### Synchronization

```bash
# Check sync status
python scripts/sync/sync_memory_backends.py --status

# Preview sync (dry run)
python scripts/sync/sync_memory_backends.py --dry-run

# Execute sync
python scripts/sync/sync_memory_backends.py --direction bidirectional
```

---

## 🏗️ Project-Specific Context

### Key Files to Add

| Purpose | Files to Include |
|---------|-----------------|
| **Storage backends** | `@src/mcp_memory_service/storage/` |
| **MCP protocol** | `@src/mcp_memory_service/server.py` |
| **Web interface** | `@src/mcp_memory_service/web/` |
| **Configuration** | `@.env.example`, `@src/mcp_memory_service/config.py` |
| **Tests** | `@tests/test_*.py` |
| **Scripts** | `@scripts/server/`, `@scripts/sync/` |

### Common Debugging Patterns

```bash
# 1. HTTP Server not responding
python scripts/server/check_http_server.py -v
tasklist | findstr python  # Check if running
scripts/server/start_http_server.bat  # Restart

# 2. Wrong backend active
python scripts/validation/diagnose_backend_config.py
# Check: .env file, environment variables, Claude Desktop config

# 3. Missing memories
python scripts/sync/sync_memory_backends.py --status
# Compare: Cloudflare count vs SQLite count

# 4. Service logs
@http_server.log  # Add to context for troubleshooting
```

---

## 📚 Architecture Quick Reference

### Storage Backends

| Backend | Performance | Use Case | Config Variable |
|---------|-------------|----------|-----------------|
| **Hybrid** ⭐ | 5ms read | Production (recommended) | `MCP_MEMORY_STORAGE_BACKEND=hybrid` |
| **SQLite-vec** | 5ms read | Development, single-user | `MCP_MEMORY_STORAGE_BACKEND=sqlite_vec` |
| **Cloudflare** | Network-dependent | Legacy cloud-only | `MCP_MEMORY_STORAGE_BACKEND=cloudflare` |

### Key Directories

```
mcp-memory-service/
├── src/mcp_memory_service/
│   ├── server.py              # MCP protocol implementation
│   ├── storage/
│   │   ├── base.py            # Abstract storage interface
│   │   ├── sqlite_vec.py      # SQLite-vec backend
│   │   ├── cloudflare.py      # Cloudflare backend
│   │   └── hybrid.py          # Hybrid backend (recommended)
│   ├── web/
│   │   ├── app.py             # FastAPI server
│   │   └── static/            # Dashboard UI
│   └── config.py              # Configuration management
├── scripts/
│   ├── server/                # HTTP server management
│   ├── sync/                  # Backend synchronization
│   └── validation/            # Configuration validation
└── tests/                     # Test suite
```

---

## 🔧 Environment Variables

**Essential Configuration** (in `.env` file):

```bash
# Backend Selection
MCP_MEMORY_STORAGE_BACKEND=hybrid  # hybrid|sqlite_vec|cloudflare

# Cloudflare (required for hybrid/cloudflare backends)
CLOUDFLARE_API_TOKEN=your-token
CLOUDFLARE_ACCOUNT_ID=your-account
CLOUDFLARE_D1_DATABASE_ID=your-d1-id
CLOUDFLARE_VECTORIZE_INDEX=mcp-memory-index

# Hybrid-Specific
MCP_HYBRID_SYNC_INTERVAL=300      # 5 minutes
MCP_HYBRID_BATCH_SIZE=50
MCP_HYBRID_SYNC_ON_STARTUP=true

# HTTP Server
MCP_HTTP_ENABLED=true
MCP_HTTPS_ENABLED=true
MCP_API_KEY=your-generated-key
```

---

## 🐛 Troubleshooting Checklist

### HTTP Server Issues
- [ ] Check if server is running: `python scripts/server/check_http_server.py -v`
- [ ] Review logs: `@http_server.log`
- [ ] Restart server: `scripts/server/start_http_server.bat`
- [ ] Verify port 8000 is free: `netstat -ano | findstr :8000`

### Backend Configuration Issues
- [ ] Run diagnostic: `python scripts/validation/diagnose_backend_config.py`
- [ ] Check `.env` file exists and has correct values
- [ ] Verify Cloudflare credentials are valid
- [ ] Confirm environment variables loaded: check server startup logs

### Missing Memories
- [ ] Check sync status: `python scripts/sync/sync_memory_backends.py --status`
- [ ] Compare memory counts: Cloudflare vs SQLite
- [ ] Run manual sync: `python scripts/sync/sync_memory_backends.py --dry-run`
- [ ] Check for duplicates: Look for content hash matches

### Performance Issues
- [ ] Verify backend: Hybrid should show ~5ms read times
- [ ] Check disk space: Litestream requires adequate space
- [ ] Monitor background sync: Check `http_server.log` for sync logs
- [ ] Review embedding model cache: Should be loaded once

---

## 💡 Pro Tips

### Efficient Context Management

```bash
# Start specific, expand as needed
@src/mcp_memory_service/storage/hybrid.py  # Specific file
@src/mcp_memory_service/storage/           # Whole module if needed

# Remove context when done
# Use Esc to cancel unnecessary context additions
```

### Multi-Step Tasks

```bash
# Always use TodoWrite for complex tasks
# Claude will create and manage task list automatically

# Example: "Implement new backend"
# 1. Research existing backends
# 2. Create new backend class
# 3. Implement abstract methods
# 4. Add configuration
# 5. Write tests
# 6. Update documentation
```

### Testing Strategy

```bash
# Test incrementally
pytest tests/test_storage.py::TestHybridBackend -v

# Run full suite before committing
pytest tests/ -v

# Check coverage
pytest tests/ --cov=src/mcp_memory_service --cov-report=term
```

### Git Workflow with Claude Code

```bash
# Let Claude help with commits
git status  # Claude reviews changes
git diff    # Claude explains changes

# Use semantic commits
git commit -m "feat: add new backend support"
git commit -m "fix: resolve sync timing issue"
git commit -m "docs: update configuration guide"
```

---

## 📖 Additional Resources

- **Full Documentation**: `@CLAUDE.md` (project-specific guide)
- **Global Best Practices**: `~/.claude/CLAUDE.md` (cross-project)
- **Wiki**: https://github.com/doobidoo/mcp-memory-service/wiki
- **Troubleshooting**: See Wiki for comprehensive troubleshooting guide

---

**Last Updated**: 2025-10-08

```

--------------------------------------------------------------------------------
/docs/technical/development.md:
--------------------------------------------------------------------------------

```markdown
# MCP Memory Service - Development Guidelines

## Commands
- Run memory server: `python scripts/run_memory_server.py`
- Run tests: `pytest tests/`
- Run specific test: `pytest tests/test_memory_ops.py::test_store_memory -v`
- Check environment: `python scripts/verify_environment_enhanced.py`
- Windows installation: `python scripts/install_windows.py`
- Build package: `python -m build`

## Installation Guidelines
- Always install in a virtual environment: `python -m venv venv`
- Use `install.py` for cross-platform installation
- Windows requires special PyTorch installation with 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
  ```
- For recursion errors, run: `python scripts/fix_sitecustomize.py`

## Code Style
- Python 3.10+ with type hints
- Use dataclasses for models (see `models/memory.py`)
- Triple-quoted docstrings for modules and functions
- Async/await pattern for all I/O operations
- Error handling with specific exception types and informative messages
- Logging with appropriate levels for different severity
- Commit messages follow semantic release format: `type(scope): message`

## Project Structure
- `src/mcp_memory_service/` - Core package code
  - `models/` - Data models
  - `storage/` - Database abstraction
  - `utils/` - Helper functions
  - `server.py` - MCP protocol implementation
- `scripts/` - Utility scripts
- `memory_wrapper.py` - Windows wrapper script
- `install.py` - Cross-platform installation script

## Dependencies
- ChromaDB (0.5.23) for vector database
- sentence-transformers (>=2.2.2) for embeddings
- PyTorch (platform-specific installation)
- MCP protocol (>=1.0.0, <2.0.0) for client-server communication

## Troubleshooting

### Common Issues

- For Windows installation issues, use `scripts/install_windows.py`
- Apple Silicon requires Python 3.10+ built for ARM64  
- CUDA issues: verify with `torch.cuda.is_available()`
- For MCP protocol issues, check `server.py` for required methods

### MCP Server Configuration Issues

If you encounter MCP server failures or "ModuleNotFoundError" issues:

#### Missing http_server_manager Module
**Symptoms:**
- Server fails with "No module named 'mcp_memory_service.utils.http_server_manager'"
- MCP server shows as "failed" in Claude Code

**Diagnosis:**
1. Test server directly: `python -m src.mcp_memory_service.server --debug`
2. Check if the error occurs during eager storage initialization
3. Look for HTTP server coordination mode detection

**Solution:**
The `http_server_manager.py` module handles multi-client coordination. If missing, create it with:
- `auto_start_http_server_if_needed()` function
- Port detection and server startup logic
- Integration with existing `port_detection.py` utilities

#### Storage Backend Issues
**Symptoms:**
- "vec0 constructor error: Unknown table option" (older sqlite-vec versions)
- Server initialization fails with storage errors

**Diagnosis:**
1. Test each backend independently:
   - ChromaDB: `python scripts/run_memory_server.py --debug`
   - SQLite-vec: `MCP_MEMORY_STORAGE_BACKEND=sqlite_vec python -m src.mcp_memory_service.server --debug`
2. Check database health: Use MCP tools to call `check_database_health`

**Solution:**
- Ensure sqlite-vec is properly installed and compatible
- Both backends should work when properly configured
- SQLite-vec uses direct storage mode when HTTP coordination fails

#### MCP Configuration Cleanup
When multiple servers conflict or fail:

1. **Backup configurations:**
   ```bash
   cp .mcp.json .mcp.json.backup
   ```

2. **Remove failing servers** from `.mcp.json` while keeping working ones

3. **Test each backend separately:**
   - ChromaDB backend: Uses `scripts/run_memory_server.py`
   - SQLite-vec backend: Uses `python -m src.mcp_memory_service.server` with `MCP_MEMORY_STORAGE_BACKEND=sqlite_vec`

4. **Verify functionality** through MCP tools before re-enabling servers

### Collaborative Debugging with Claude Code

When troubleshooting complex MCP issues, consider this collaborative approach between developer and Claude Code:

#### Systematic Problem-Solving Partnership
1. **Developer identifies the symptom** (e.g., "memory server shows as failed")
2. **Claude Code conducts comprehensive diagnosis:**
   - Tests current functionality with MCP tools
   - Examines server logs and error messages  
   - Checks configuration files and git history
   - Identifies root causes through systematic analysis

3. **Collaborative investigation approach:**
   - **Developer requests:** "Check both ways - verify current service works AND fix the failing alternative"
   - **Claude Code responds:** Creates todo lists, tests each component independently, provides detailed analysis
   - **Developer provides context:** Domain knowledge, constraints, preferences

4. **Methodical fix implementation:**
   - Back up configurations before changes
   - Fix issues incrementally with testing at each step
   - Document the process for future reference
   - Commit meaningful changes with proper commit messages

#### Benefits of This Approach
- **Comprehensive coverage:** Nothing gets missed when both perspectives combine
- **Knowledge transfer:** Claude Code documents the process, developer retains understanding
- **Systematic methodology:** Todo lists and step-by-step verification prevent overlooked issues
- **Persistent knowledge:** Using the memory service itself to store troubleshooting solutions

#### Example Workflow
```
Developer: "MCP memory server is failing"
↓
Claude Code: Creates todo list, tests current state, identifies missing module
↓  
Developer: "Let's fix it but keep the working parts"
↓
Claude Code: Backs up configs, fixes incrementally, tests each component
↓
Developer: "This should be documented"
↓
Claude Code: Updates documentation, memorizes the solution
↓
Both: Commit, push, and ensure knowledge is preserved
```

This collaborative model leverages Claude Code's systematic analysis capabilities with the developer's domain expertise and decision-making authority.

## Debugging with MCP-Inspector

To debug the MCP-MEMORY-SERVICE using the [MCP-Inspector](https://modelcontextprotocol.io/docs/tools/inspector) tool, you can use the following command pattern:

```bash
MCP_MEMORY_CHROMA_PATH="/path/to/your/chroma_db" MCP_MEMORY_BACKUPS_PATH="/path/to/your/backups" npx @modelcontextprotocol/inspector uv --directory /path/to/mcp-memory-service run memory
```

Replace the paths with your specific directories:
- `/path/to/your/chroma_db`: Location where Chroma database files are stored
- `/path/to/your/backups`: Location for memory backups
- `/path/to/mcp-memory-service`: Directory containing the MCP-MEMORY-SERVICE code

For example:
```bash
MCP_MEMORY_CHROMA_PATH="~/Library/Mobile Documents/com~apple~CloudDocs/AI/claude-memory/chroma_db" MCP_MEMORY_BACKUPS_PATH="~/Library/Mobile Documents/com~apple~CloudDocs/AI/claude-memory/backups" npx @modelcontextprotocol/inspector uv --directory ~/Documents/GitHub/mcp-memory-service run memory
```

This command sets the required environment variables and runs the memory service through the inspector tool for debugging purposes.

```

--------------------------------------------------------------------------------
/scripts/pr/run_pyscn_analysis.sh:
--------------------------------------------------------------------------------

```bash
#!/bin/bash
# scripts/pr/run_pyscn_analysis.sh - Run pyscn comprehensive code quality analysis
#
# Usage:
#   bash scripts/pr/run_pyscn_analysis.sh [--pr PR_NUMBER] [--threshold SCORE]
#
# Options:
#   --pr PR_NUMBER    Post results as PR comment (requires gh CLI)
#   --threshold SCORE Minimum health score (default: 50, blocks below this)
#
# Examples:
#   bash scripts/pr/run_pyscn_analysis.sh                    # Local analysis
#   bash scripts/pr/run_pyscn_analysis.sh --pr 123           # Analyze and comment on PR #123
#   bash scripts/pr/run_pyscn_analysis.sh --threshold 70     # Require health score ≥70

set -e

# Colors for output
RED='\033[0;31m'
YELLOW='\033[1;33m'
GREEN='\033[0;32m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

# Parse arguments
PR_NUMBER=""
THRESHOLD=50  # Default: block if health score <50

while [[ $# -gt 0 ]]; do
    case $1 in
        --pr)
            PR_NUMBER="$2"
            shift 2
            ;;
        --threshold)
            THRESHOLD="$2"
            shift 2
            ;;
        *)
            echo "Unknown option: $1"
            echo "Usage: $0 [--pr PR_NUMBER] [--threshold SCORE]"
            exit 1
            ;;
    esac
done

# Check for pyscn
if ! command -v pyscn &> /dev/null; then
    echo -e "${RED}❌ pyscn not found${NC}"
    echo ""
    echo "Install pyscn with:"
    echo "  pip install pyscn"
    echo ""
    echo "Repository: https://github.com/ludo-technologies/pyscn"
    exit 1
fi

echo -e "${BLUE}=== pyscn Code Quality Analysis ===${NC}"
echo ""

# Create reports directory if needed
mkdir -p .pyscn/reports

# Run pyscn analysis
echo "Running pyscn analysis (this may take 30-60 seconds)..."
echo ""

# Generate timestamp for report
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
REPORT_FILE=".pyscn/reports/analyze_${TIMESTAMP}.html"
JSON_FILE=".pyscn/reports/analyze_${TIMESTAMP}.json"

# Run analysis (HTML report)
if pyscn analyze . --output "$REPORT_FILE" 2>&1 | tee /tmp/pyscn_output.log; then
    echo -e "${GREEN}✓${NC} Analysis complete"
else
    echo -e "${RED}❌ Analysis failed${NC}"
    cat /tmp/pyscn_output.log
    exit 1
fi

# Extract metrics from HTML report using grep/sed
# Note: This is a simple parser - adjust patterns if pyscn output format changes
HEALTH_SCORE=$(grep -o 'Health Score: [0-9]*' "$REPORT_FILE" | head -1 | grep -o '[0-9]*' || echo "0")
COMPLEXITY_SCORE=$(grep -o '<span class="score-value">[0-9]*</span>' "$REPORT_FILE" | head -1 | sed 's/<[^>]*>//g' || echo "0")
DEAD_CODE_SCORE=$(grep -o '<span class="score-value">[0-9]*</span>' "$REPORT_FILE" | sed -n '2p' | sed 's/<[^>]*>//g' || echo "0")
DUPLICATION_SCORE=$(grep -o '<span class="score-value">[0-9]*</span>' "$REPORT_FILE" | sed -n '3p' | sed 's/<[^>]*>//g' || echo "0")

# Extract detailed metrics
TOTAL_FUNCTIONS=$(grep -o '<div class="metric-value">[0-9]*</div>' "$REPORT_FILE" | head -1 | sed 's/<[^>]*>//g' || echo "0")
AVG_COMPLEXITY=$(grep -o '<div class="metric-value">[0-9.]*</div>' "$REPORT_FILE" | sed -n '3p' | sed 's/<[^>]*>//g' || echo "0")
MAX_COMPLEXITY=$(grep -o '<div class="metric-value">[0-9]*</div>' "$REPORT_FILE" | sed -n '3p' | sed 's/<[^>]*>//g' || echo "0")
DUPLICATION_PCT=$(grep -o '<div class="metric-value">[0-9.]*%</div>' "$REPORT_FILE" | head -1 | sed 's/<[^>]*>//g' || echo "0%")
DEAD_CODE_ISSUES=$(grep -o '<div class="metric-value">[0-9]*</div>' "$REPORT_FILE" | sed -n '4p' | sed 's/<[^>]*>//g' || echo "0")
ARCHITECTURE_VIOLATIONS=$(grep -o '<div class="metric-value">[0-9]*</div>' "$REPORT_FILE" | tail -2 | head -1 | sed 's/<[^>]*>//g' || echo "0")

echo ""
echo -e "${BLUE}=== Analysis Results ===${NC}"
echo ""
echo "📊 Overall Health Score: $HEALTH_SCORE/100"
echo ""
echo "Quality Metrics:"
echo "  - Complexity: $COMPLEXITY_SCORE/100 (Avg: $AVG_COMPLEXITY, Max: $MAX_COMPLEXITY)"
echo "  - Dead Code: $DEAD_CODE_SCORE/100 ($DEAD_CODE_ISSUES issues)"
echo "  - Duplication: $DUPLICATION_SCORE/100 ($DUPLICATION_PCT duplication)"
echo ""
echo "📄 Report: $REPORT_FILE"
echo ""

# Determine status
EXIT_CODE=0
STATUS="✅ PASSED"
EMOJI="✅"
COLOR=$GREEN

if [ "$HEALTH_SCORE" -lt "$THRESHOLD" ]; then
    STATUS="🔴 BLOCKED"
    EMOJI="🔴"
    COLOR=$RED
    EXIT_CODE=1
elif [ "$HEALTH_SCORE" -lt 70 ]; then
    STATUS="⚠️  WARNING"
    EMOJI="⚠️"
    COLOR=$YELLOW
fi

echo -e "${COLOR}${STATUS}${NC} - Health score: $HEALTH_SCORE (threshold: $THRESHOLD)"
echo ""

# Generate recommendations
RECOMMENDATIONS=""

if [ "$HEALTH_SCORE" -lt 50 ]; then
    RECOMMENDATIONS="**🚨 Critical Action Required:**
- Health score below 50 is a release blocker
- Focus on top 5 highest complexity functions
- Remove dead code before proceeding
"
elif [ "$HEALTH_SCORE" -lt 70 ]; then
    RECOMMENDATIONS="**⚠️  Improvement Recommended:**
- Plan refactoring sprint within 2 weeks
- Track high-complexity functions on project board
- Review duplication patterns for consolidation opportunities
"
fi

# Check for critical issues
CRITICAL_COMPLEXITY=""
if [ "$MAX_COMPLEXITY" -gt 10 ]; then
    CRITICAL_COMPLEXITY="- ⚠️  Functions with complexity >10 detected (Max: $MAX_COMPLEXITY)
"
fi

CRITICAL_DUPLICATION=""
DUPLICATION_NUM=$(echo "$DUPLICATION_PCT" | sed 's/%//')
if (( $(echo "$DUPLICATION_NUM > 5.0" | bc -l) )); then
    CRITICAL_DUPLICATION="- ⚠️  Code duplication above 5% threshold ($DUPLICATION_PCT)
"
fi

# Post to PR if requested
if [ -n "$PR_NUMBER" ]; then
    if ! command -v gh &> /dev/null; then
        echo -e "${YELLOW}⚠️  gh CLI not found, skipping PR comment${NC}"
    else
        echo "Posting results to PR #$PR_NUMBER..."

        COMMENT_BODY="## ${EMOJI} pyscn Code Quality Analysis

**Health Score:** $HEALTH_SCORE/100

### Quality Metrics

| Metric | Score | Details |
|--------|-------|---------|
| 🔢 Complexity | $COMPLEXITY_SCORE/100 | Avg: $AVG_COMPLEXITY, Max: $MAX_COMPLEXITY |
| 💀 Dead Code | $DEAD_CODE_SCORE/100 | $DEAD_CODE_ISSUES issues |
| 📋 Duplication | $DUPLICATION_SCORE/100 | $DUPLICATION_PCT code duplication |
| 🏗️  Architecture | N/A | $ARCHITECTURE_VIOLATIONS violations |

### Status

$STATUS (Threshold: $THRESHOLD)

${CRITICAL_COMPLEXITY}${CRITICAL_DUPLICATION}${RECOMMENDATIONS}

### Full Report

View detailed analysis: [HTML Report](.pyscn/reports/analyze_${TIMESTAMP}.html)

---

<details>
<summary>📖 About pyscn</summary>

pyscn (Python Static Code Navigator) provides comprehensive static analysis including:
- Cyclomatic complexity analysis
- Dead code detection
- Code duplication (clone detection)
- Coupling metrics (CBO)
- Dependency graph analysis
- Architecture violation detection

Repository: https://github.com/ludo-technologies/pyscn
</details>"

        echo "$COMMENT_BODY" | gh pr comment "$PR_NUMBER" --body-file -
        echo -e "${GREEN}✓${NC} Posted comment to PR #$PR_NUMBER"
    fi
fi

# Summary
echo ""
echo -e "${BLUE}=== Summary ===${NC}"
echo ""

if [ $EXIT_CODE -eq 0 ]; then
    echo -e "${GREEN}✅ Quality checks passed${NC}"
    echo ""
    echo "Health score ($HEALTH_SCORE) meets threshold ($THRESHOLD)"
else
    echo -e "${RED}❌ Quality checks failed${NC}"
    echo ""
    echo "Health score ($HEALTH_SCORE) below threshold ($THRESHOLD)"
    echo ""
    echo "Action required before merging:"
    echo "  1. Review full report: open $REPORT_FILE"
    echo "  2. Address high-complexity functions (complexity >10)"
    echo "  3. Remove dead code ($DEAD_CODE_ISSUES issues)"
    echo "  4. Reduce duplication where feasible"
    echo ""
fi

exit $EXIT_CODE

```

--------------------------------------------------------------------------------
/src/mcp_memory_service/sync/exporter.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.

"""
Memory export functionality for database synchronization.
"""

import json
import os
import platform
import logging
from datetime import datetime
from pathlib import Path
from typing import List, Dict, Any, Optional

from ..models.memory import Memory
from ..storage.base import MemoryStorage

logger = logging.getLogger(__name__)


class MemoryExporter:
    """
    Exports memories from a storage backend to JSON format.
    
    Preserves all metadata, timestamps, and adds source tracking for
    multi-machine synchronization workflows.
    """
    
    def __init__(self, storage: MemoryStorage):
        """
        Initialize the exporter.
        
        Args:
            storage: The memory storage backend to export from
        """
        self.storage = storage
        self.machine_name = self._get_machine_name()
    
    def _get_machine_name(self) -> str:
        """Get a unique machine identifier."""
        # Try various methods to get a unique machine name
        machine_name = (
            os.environ.get('COMPUTERNAME') or  # Windows
            os.environ.get('HOSTNAME') or      # Linux/macOS
            platform.node() or                # Platform module
            'unknown-machine'
        )
        return machine_name.lower().replace(' ', '-')
    
    async def export_to_json(
        self, 
        output_file: Path,
        include_embeddings: bool = False,
        filter_tags: Optional[List[str]] = None
    ) -> Dict[str, Any]:
        """
        Export all memories to JSON format.
        
        Args:
            output_file: Path to write the JSON export
            include_embeddings: Whether to include embedding vectors (large)
            filter_tags: Only export memories with these tags (optional)
            
        Returns:
            Export metadata dictionary with statistics
        """
        logger.info(f"Starting memory export to {output_file}")
        
        # Get all memories from storage
        all_memories = await self._get_filtered_memories(filter_tags)
        
        # Create export metadata
        export_metadata = {
            "source_machine": self.machine_name,
            "export_timestamp": datetime.now().isoformat(),
            "total_memories": len(all_memories),
            "database_path": str(self.storage.db_path) if hasattr(self.storage, 'db_path') else 'unknown',
            "platform": platform.system(),
            "python_version": platform.python_version(),
            "include_embeddings": include_embeddings,
            "filter_tags": filter_tags,
            "exporter_version": "5.0.1"
        }
        
        # Convert memories to exportable format
        exported_memories = []
        for memory in all_memories:
            memory_dict = await self._memory_to_dict(memory, include_embeddings)
            exported_memories.append(memory_dict)
        
        # Create final export structure
        export_data = {
            "export_metadata": export_metadata,
            "memories": exported_memories
        }
        
        # Write to JSON file
        output_file.parent.mkdir(parents=True, exist_ok=True)
        with open(output_file, 'w', encoding='utf-8') as f:
            json.dump(export_data, f, indent=2, ensure_ascii=False)
        
        # Log success
        file_size = output_file.stat().st_size
        logger.info(f"Export completed: {len(all_memories)} memories written to {output_file}")
        logger.info(f"File size: {file_size / 1024 / 1024:.2f} MB")
        
        # Return summary statistics
        return {
            "success": True,
            "exported_count": len(all_memories),
            "output_file": str(output_file),
            "file_size_bytes": file_size,
            "source_machine": self.machine_name,
            "export_timestamp": export_metadata["export_timestamp"]
        }
    
    async def _get_filtered_memories(self, filter_tags: Optional[List[str]]) -> List[Memory]:
        """Get memories with optional tag filtering."""
        if not filter_tags:
            # Get all memories
            return await self.storage.get_all_memories()
        
        # Filter by tags if specified
        filtered_memories = []
        all_memories = await self.storage.get_all_memories()
        
        for memory in all_memories:
            if any(tag in memory.tags for tag in filter_tags):
                filtered_memories.append(memory)
        
        return filtered_memories
    
    async def _memory_to_dict(self, memory: Memory, include_embeddings: bool) -> Dict[str, Any]:
        """Convert a Memory object to a dictionary for JSON export."""
        memory_dict = {
            "content": memory.content,
            "content_hash": memory.content_hash,
            "tags": memory.tags,
            "created_at": memory.created_at,  # Preserve original timestamp
            "updated_at": memory.updated_at,
            "memory_type": memory.memory_type,
            "metadata": memory.metadata or {},
            "export_source": self.machine_name
        }
        
        # Add embedding if requested and available
        if include_embeddings and hasattr(memory, 'embedding') and memory.embedding:
            memory_dict["embedding"] = memory.embedding.tolist() if hasattr(memory.embedding, 'tolist') else memory.embedding
        
        return memory_dict
    
    async def export_summary(self) -> Dict[str, Any]:
        """
        Get a summary of what would be exported without actually exporting.
        
        Returns:
            Summary statistics about the memories in the database
        """
        all_memories = await self.storage.get_all_memories()
        
        # Analyze tags
        tag_counts = {}
        memory_types = {}
        date_range = {"earliest": None, "latest": None}
        
        for memory in all_memories:
            # Count tags
            for tag in memory.tags:
                tag_counts[tag] = tag_counts.get(tag, 0) + 1
            
            # Count memory types
            memory_types[memory.memory_type] = memory_types.get(memory.memory_type, 0) + 1
            
            # Track date range
            if date_range["earliest"] is None or memory.created_at < date_range["earliest"]:
                date_range["earliest"] = memory.created_at
            if date_range["latest"] is None or memory.created_at > date_range["latest"]:
                date_range["latest"] = memory.created_at
        
        return {
            "total_memories": len(all_memories),
            "machine_name": self.machine_name,
            "tag_counts": dict(sorted(tag_counts.items(), key=lambda x: x[1], reverse=True)),
            "memory_types": memory_types,
            "date_range": date_range,
            "estimated_json_size_mb": len(all_memories) * 0.001  # Rough estimate
        }
```

--------------------------------------------------------------------------------
/scripts/testing/test_memory_api.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.

"""
Test script for memory CRUD operations via HTTP API.

This script tests the basic memory operations to ensure they work correctly.
"""

import asyncio
import aiohttp
import json
import time
from typing import Dict, Any

BASE_URL = "http://localhost:8000"

async def test_memory_crud():
    """Test the complete CRUD workflow for memories."""
    
    async with aiohttp.ClientSession() as session:
        print("Testing Memory CRUD Operations")
        print("=" * 50)
        
        # Test 1: Health check
        print("\n[1] Testing health check...")
        try:
            async with session.get(f"{BASE_URL}/api/health") as resp:
                if resp.status == 200:
                    health = await resp.json()
                    print(f"[PASS] Health check passed: {health['status']}")
                else:
                    print(f"[FAIL] Health check failed: {resp.status}")
                    return
        except Exception as e:
            print(f"[FAIL] Cannot connect to server: {e}")
            print("NOTE: Make sure the server is running with: python scripts/run_http_server.py")
            return
        
        # Test 2: Store a memory
        print("\n[2] Testing memory storage...")
        test_memory = {
            "content": "This is a test memory for CRUD operations",
            "tags": ["test", "crud", "api"],
            "memory_type": "test",
            "metadata": {"test_run": time.time(), "importance": "high"}
        }
        
        try:
            async with session.post(
                f"{BASE_URL}/api/memories",
                json=test_memory,
                headers={"Content-Type": "application/json"}
            ) as resp:
                if resp.status == 200:
                    result = await resp.json()
                    if result["success"]:
                        content_hash = result["content_hash"]
                        print(f"[PASS] Memory stored successfully")
                        print(f"   Content hash: {content_hash[:16]}...")
                        print(f"   Message: {result['message']}")
                    else:
                        print(f"[FAIL] Memory storage failed: {result['message']}")
                        return
                else:
                    print(f"[FAIL] Memory storage failed: {resp.status}")
                    error = await resp.text()
                    print(f"   Error: {error}")
                    return
        except Exception as e:
            print(f"[FAIL] Memory storage error: {e}")
            return
        
        # Test 3: List memories
        print("\n[3] Testing memory listing...")
        try:
            async with session.get(f"{BASE_URL}/api/memories?page=1&page_size=5") as resp:
                if resp.status == 200:
                    result = await resp.json()
                    memories = result["memories"]
                    print(f"✅ Retrieved {len(memories)} memories")
                    print(f"   Total memories: {result['total']}")
                    print(f"   Page: {result['page']}, Has more: {result['has_more']}")
                    
                    if memories:
                        print(f"   First memory preview: {memories[0]['content'][:50]}...")
                else:
                    print(f"❌ Memory listing failed: {resp.status}")
                    error = await resp.text()
                    print(f"   Error: {error}")
        except Exception as e:
            print(f"❌ Memory listing error: {e}")
        
        # Test 4: Get specific memory
        print("\n4️⃣  Testing specific memory retrieval...")
        try:
            async with session.get(f"{BASE_URL}/api/memories/{content_hash}") as resp:
                if resp.status == 200:
                    memory = await resp.json()
                    print(f"✅ Retrieved specific memory")
                    print(f"   Content: {memory['content'][:50]}...")
                    print(f"   Tags: {memory['tags']}")
                    print(f"   Type: {memory['memory_type']}")
                elif resp.status == 404:
                    print(f"⚠️  Memory not found (this might be expected if get-by-hash isn't implemented)")
                else:
                    print(f"❌ Memory retrieval failed: {resp.status}")
                    error = await resp.text()
                    print(f"   Error: {error}")
        except Exception as e:
            print(f"❌ Memory retrieval error: {e}")
        
        # Test 5: Filter by tag
        print("\n5️⃣  Testing tag filtering...")
        try:
            async with session.get(f"{BASE_URL}/api/memories?tag=test") as resp:
                if resp.status == 200:
                    result = await resp.json()
                    memories = result["memories"]
                    print(f"✅ Retrieved {len(memories)} memories with tag 'test'")
                    if memories:
                        for memory in memories[:2]:  # Show first 2
                            print(f"   - {memory['content'][:40]}... (tags: {memory['tags']})")
                else:
                    print(f"❌ Tag filtering failed: {resp.status}")
        except Exception as e:
            print(f"❌ Tag filtering error: {e}")
        
        # Test 6: Delete memory
        print("\n6️⃣  Testing memory deletion...")
        try:
            async with session.delete(f"{BASE_URL}/api/memories/{content_hash}") as resp:
                if resp.status == 200:
                    result = await resp.json()
                    if result["success"]:
                        print(f"✅ Memory deleted successfully")
                        print(f"   Message: {result['message']}")
                    else:
                        print(f"❌ Memory deletion failed: {result['message']}")
                else:
                    print(f"❌ Memory deletion failed: {resp.status}")
                    error = await resp.text()
                    print(f"   Error: {error}")
        except Exception as e:
            print(f"❌ Memory deletion error: {e}")
        
        # Test 7: Verify deletion
        print("\n7️⃣  Verifying memory deletion...")
        try:
            async with session.get(f"{BASE_URL}/api/memories/{content_hash}") as resp:
                if resp.status == 404:
                    print(f"✅ Memory successfully deleted (404 as expected)")
                elif resp.status == 200:
                    print(f"⚠️  Memory still exists after deletion")
                else:
                    print(f"❓ Unexpected response: {resp.status}")
        except Exception as e:
            print(f"❌ Deletion verification error: {e}")
        
        print("\n" + "=" * 50)
        print("🎉 Memory CRUD testing completed!")


if __name__ == "__main__":
    asyncio.run(test_memory_crud())
```

--------------------------------------------------------------------------------
/docs/first-time-setup.md:
--------------------------------------------------------------------------------

```markdown
# First-Time Setup Guide

This guide explains what to expect when running MCP Memory Service for the first time.

## 🎯 What to Expect on First Run

When you start the MCP Memory Service for the first time, you'll see several warnings and messages. **This is completely normal behavior** as the service initializes and downloads necessary components.

## 📋 Normal First-Time Warnings

### 1. Snapshots Directory Warning
```
WARNING:mcp_memory_service.storage.sqlite_vec:Failed to load from cache: No snapshots directory
```

**What it means:** 
- The service is checking for previously downloaded embedding models
- On first run, no cache exists yet, so this warning appears
- The service will automatically download the model

**This is normal:** ✅ Expected on first run

### 2. TRANSFORMERS_CACHE Warning
```
WARNING: Using TRANSFORMERS_CACHE is deprecated
```

**What it means:**
- This is an informational warning from the Hugging Face library
- It doesn't affect the service functionality
- The service handles caching internally

**This is normal:** ✅ Can be safely ignored

### 3. Model Download Progress
```
Downloading model 'all-MiniLM-L6-v2'...
```

**What it means:**
- The service is downloading the embedding model (approximately 25MB)
- This happens only once on first setup
- Download time: 1-2 minutes on average internet connection

**This is normal:** ✅ One-time download

## 🚦 Success Indicators

After successful first-time setup, you should see:

```
INFO: SQLite-vec storage initialized successfully with embedding dimension: 384
INFO: Memory service started on port 8443
INFO: Ready to accept connections
```

## 📊 First-Time Setup Timeline

| Step | Duration | What's Happening |
|------|----------|-----------------|
| 1. Service Start | Instant | Loading configuration |
| 2. Cache Check | 1-2 seconds | Checking for existing models |
| 3. Model Download | 1-2 minutes | Downloading embedding model (~25MB) |
| 4. Model Loading | 5-10 seconds | Loading model into memory |
| 5. Database Init | 2-3 seconds | Creating database structure |
| 6. Ready | - | Service is ready to use |

**Total first-time setup:** 2-3 minutes

## 🔄 Subsequent Runs

After the first successful run:
- No download warnings will appear
- Model loads from cache (5-10 seconds)
- Service starts much faster (10-15 seconds total)

## 🐍 Python 3.13 Compatibility

### Known Issues
Python 3.13 users may encounter installation issues with **sqlite-vec** due to missing pre-built wheels. The installer now includes automatic fallback methods:

1. **Automatic Retry Logic**: Tries multiple installation strategies
2. **Source Building**: Attempts to build from source if wheels unavailable
3. **GitHub Installation**: Falls back to installing directly from repository
4. **Backend Switching**: Option to switch to ChromaDB if sqlite-vec fails

### Recommended Solutions
If you encounter sqlite-vec installation failures on Python 3.13:

**Option 1: Use Python 3.12 (Recommended)**
```bash
# macOS
brew install [email protected]
python3.12 -m venv .venv
source .venv/bin/activate
python install.py

# Ubuntu/Linux
sudo apt install python3.12 python3.12-venv
python3.12 -m venv .venv
source .venv/bin/activate
python install.py
```

**Option 2: Use ChromaDB Backend**
```bash
python install.py --storage-backend chromadb
```

**Option 3: Manual sqlite-vec Installation**
```bash
# Try building from source
pip install --no-binary :all: sqlite-vec

# Or install from GitHub
pip install git+https://github.com/asg017/sqlite-vec.git#subdirectory=python
```

## 🍎 macOS SQLite Extension Issues

### Problem: `AttributeError: 'sqlite3.Connection' object has no attribute 'enable_load_extension'`

This error occurs on **macOS with system Python** because it's not compiled with SQLite extension support.

**Why this happens:**
- macOS system Python lacks `--enable-loadable-sqlite-extensions`
- The bundled SQLite library doesn't support loadable extensions
- This is a security-focused default configuration

**Solutions:**

**Option 1: Homebrew Python (Recommended)**
```bash
# Install Python via Homebrew (includes extension support)
brew install python
hash -r  # Refresh command cache
python3 --version  # Verify you're using Homebrew Python

# Then install MCP Memory Service
python3 install.py
```

**Option 2: pyenv with Extension Support**
```bash
# Install pyenv if not already installed
brew install pyenv

# Install Python with extension support
PYTHON_CONFIGURE_OPTS="--enable-loadable-sqlite-extensions" pyenv install 3.12.0
pyenv local 3.12.0

# Verify extension support
python3 -c "import sqlite3; conn=sqlite3.connect(':memory:'); conn.enable_load_extension(True); print('Extensions supported!')"
```

**Option 3: Use ChromaDB Backend**
```bash
# ChromaDB doesn't require SQLite extensions
python3 install.py --storage-backend chromadb
```

### Verification
Check if your Python supports extensions:
```bash
python3 -c "
import sqlite3
conn = sqlite3.connect(':memory:')
print('✅ Extension support available' if hasattr(conn, 'enable_load_extension') else '❌ No extension support')
"
```

## 🐧 Ubuntu/Linux Specific Notes

For Ubuntu 24 and other Linux distributions:

### Prerequisites
```bash
# System dependencies
sudo apt update
sudo apt install python3.10 python3.10-venv python3.10-dev python3-pip
sudo apt install build-essential libblas3 liblapack3 liblapack-dev libblas-dev gfortran
```

### Recommended Setup
```bash
# Create virtual environment
python3 -m venv venv
source venv/bin/activate

# Install the service
python install.py

# Start the service
uv run memory server
```

## 🔧 Troubleshooting First-Time Issues

### Issue: Download Fails
**Solution:**
- Check internet connection
- Verify firewall/proxy settings
- Clear cache and retry: `rm -rf ~/.cache/huggingface`

### Issue: "No module named 'sentence_transformers'"
**Solution:**
```bash
pip install sentence-transformers torch
```

### Issue: Permission Denied
**Solution:**
```bash
# Fix permissions
chmod +x scripts/*.sh
sudo chown -R $USER:$USER ~/.mcp_memory_service/
```

### Issue: Service Doesn't Start After Download
**Solution:**
1. Check logs: `uv run memory server --debug`
2. Verify installation: `python scripts/verify_environment.py`
3. Restart with clean state: 
   ```bash
   rm -rf ~/.mcp_memory_service
   uv run memory server
   ```

## ✅ Verification

To verify successful setup:

```bash
# Check service health
curl -k https://localhost:8443/api/health

# Or using the CLI
uv run memory health
```

Expected response:
```json
{
  "status": "healthy",
  "storage_backend": "sqlite_vec",
  "model_loaded": true
}
```

## 🎉 Setup Complete!

Once you see the success indicators and the warnings have disappeared on subsequent runs, your MCP Memory Service is fully operational and ready to use!

### Next Steps:
- [Configure Claude Desktop](../README.md#claude-desktop-integration)
- [Store your first memory](../README.md#basic-usage)
- [Explore the API](https://github.com/doobidoo/mcp-memory-service/wiki)

## 📝 Notes

- The model download is a one-time operation
- Downloaded models are cached in `~/.cache/huggingface/`
- The service creates a database in `~/.mcp_memory_service/`
- All warnings shown during first-time setup are expected behavior
- If you see different errors (not warnings), check the [Troubleshooting Guide](troubleshooting/general.md)

---

Remember: **First-time warnings are normal!** The service is working correctly and setting itself up for optimal performance.
```

--------------------------------------------------------------------------------
/tests/performance/test_hybrid_live.py:
--------------------------------------------------------------------------------

```python
#!/usr/bin/env python3
"""
Live performance test of the hybrid storage backend implementation.
Demonstrates performance, functionality, and sync capabilities under load.
"""

import asyncio
import sys
import time
import tempfile
import os
from pathlib import Path

# Add src to path for standalone execution
sys.path.insert(0, str(Path(__file__).parent.parent.parent / 'src'))

from mcp_memory_service.storage.hybrid import HybridMemoryStorage
from mcp_memory_service.models.memory import Memory
import hashlib

async def test_hybrid_storage():
    """Test the hybrid storage implementation with live demonstrations."""

    print("🚀 Testing Hybrid Storage Backend")
    print("=" * 50)

    # Create a temporary SQLite database for testing
    with tempfile.NamedTemporaryFile(suffix='.db', delete=False) as tmp_file:
        db_path = tmp_file.name

    try:
        # Initialize hybrid storage (without Cloudflare for this demo)
        print("📍 Step 1: Initializing Hybrid Storage")
        storage = HybridMemoryStorage(
            sqlite_db_path=db_path,
            embedding_model="all-MiniLM-L6-v2",
            cloudflare_config=None,  # Will operate in SQLite-only mode
            sync_interval=30,  # Short interval for demo
            batch_size=5
        )

        print("   Initializing storage backend...")
        await storage.initialize()
        print(f"   ✅ Storage initialized")
        print(f"   📊 Primary: {storage.primary.__class__.__name__}")
        print(f"   📊 Secondary: {storage.secondary.__class__.__name__ if storage.secondary else 'None (SQLite-only mode)'}")
        print(f"   📊 Sync Service: {'Running' if storage.sync_service and storage.sync_service.is_running else 'Disabled'}")
        print()

        # Test 1: Performance measurement
        print("📍 Step 2: Performance Test")
        memories_to_test = []

        for i in range(5):
            content = f"Performance test memory #{i+1} - testing hybrid storage speed"
            content_hash = hashlib.sha256(content.encode()).hexdigest()

            memory = Memory(
                content=content,
                content_hash=content_hash,
                tags=["hybrid", "test", f"batch_{i}"],
                memory_type="performance_test",
                metadata={"test_batch": i, "test_type": "performance"},
                created_at=time.time()
            )
            memories_to_test.append(memory)

        # Measure write performance
        print("   Testing write performance...")
        write_times = []
        for i, memory in enumerate(memories_to_test):
            start_time = time.time()
            success, message = await storage.store(memory)
            duration = time.time() - start_time
            write_times.append(duration)

            if success:
                print(f"   ✅ Write #{i+1}: {duration*1000:.1f}ms")
            else:
                print(f"   ❌ Write #{i+1} failed: {message}")

        avg_write_time = sum(write_times) / len(write_times)
        print(f"   📊 Average write time: {avg_write_time*1000:.1f}ms")
        print()

        # Test 2: Read performance
        print("📍 Step 3: Read Performance Test")
        read_times = []

        for i in range(3):
            start_time = time.time()
            results = await storage.retrieve("performance test", n_results=5)
            duration = time.time() - start_time
            read_times.append(duration)

            print(f"   ✅ Read #{i+1}: {duration*1000:.1f}ms ({len(results)} results)")

        avg_read_time = sum(read_times) / len(read_times)
        print(f"   📊 Average read time: {avg_read_time*1000:.1f}ms")
        print()

        # Test 3: Different operations
        print("📍 Step 4: Testing Various Operations")

        # Search by tags
        start_time = time.time()
        tagged_memories = await storage.search_by_tags(["hybrid"])
        tag_search_time = time.time() - start_time
        print(f"   ✅ Tag search: {tag_search_time*1000:.1f}ms ({len(tagged_memories)} results)")

        # Get stats
        start_time = time.time()
        stats = await storage.get_stats()
        stats_time = time.time() - start_time
        print(f"   ✅ Stats retrieval: {stats_time*1000:.1f}ms")
        print(f"      - Backend: {stats.get('storage_backend')}")
        print(f"      - Total memories: {stats.get('total_memories', 0)}")
        print(f"      - Sync enabled: {stats.get('sync_enabled', False)}")

        # Test delete
        if memories_to_test:
            test_memory = memories_to_test[0]
            start_time = time.time()
            success, message = await storage.delete(test_memory.content_hash)
            delete_time = time.time() - start_time
            print(f"   ✅ Delete operation: {delete_time*1000:.1f}ms ({'Success' if success else 'Failed'})")

        print()

        # Test 4: Concurrent operations
        print("📍 Step 5: Concurrent Operations Test")

        async def store_memory(content_suffix):
            content = f"Concurrent test memory {content_suffix}"
            content_hash = hashlib.sha256(content.encode()).hexdigest()

            memory = Memory(
                content=content,
                content_hash=content_hash,
                tags=["concurrent", "hybrid"],
                memory_type="concurrent_test",
                metadata={"test_id": content_suffix},
                created_at=time.time()
            )
            return await storage.store(memory)

        start_time = time.time()
        concurrent_tasks = [store_memory(i) for i in range(10)]
        results = await asyncio.gather(*concurrent_tasks)
        concurrent_time = time.time() - start_time

        successful_ops = sum(1 for success, _ in results if success)
        print(f"   ✅ Concurrent operations: {concurrent_time*1000:.1f}ms")
        print(f"      - Operations: 10 concurrent stores")
        print(f"      - Successful: {successful_ops}/10")
        print(f"      - Avg per operation: {(concurrent_time/10)*1000:.1f}ms")
        print()

        # Final stats
        print("📍 Step 6: Final Statistics")
        final_stats = await storage.get_stats()
        print(f"   📊 Total memories stored: {final_stats.get('total_memories', 0)}")
        print(f"   📊 Storage backend: {final_stats.get('storage_backend')}")

        if storage.sync_service:
            sync_status = await storage.sync_service.get_sync_status()
            print(f"   📊 Sync queue size: {sync_status.get('queue_size', 0)}")
            print(f"   📊 Operations processed: {sync_status.get('stats', {}).get('operations_processed', 0)}")

        print()
        print("🎉 Hybrid Storage Test Complete!")
        print("=" * 50)

        # Performance summary
        print("📊 PERFORMANCE SUMMARY:")
        print(f"   • Average Write: {avg_write_time*1000:.1f}ms")
        print(f"   • Average Read:  {avg_read_time*1000:.1f}ms")
        print(f"   • Tag Search:    {tag_search_time*1000:.1f}ms")
        print(f"   • Stats Query:   {stats_time*1000:.1f}ms")
        print(f"   • Delete Op:     {delete_time*1000:.1f}ms")
        print(f"   • Concurrent:    {(concurrent_time/10)*1000:.1f}ms per op")

        # Cleanup
        await storage.close()

    finally:
        # Clean up temp file
        if os.path.exists(db_path):
            os.unlink(db_path)

if __name__ == "__main__":
    print("🚀 Hybrid Storage Live Demo")
    print("Testing the new hybrid backend implementation...")
    print()

    # Run the async test
    asyncio.run(test_hybrid_storage())
```

--------------------------------------------------------------------------------
/.github/workflows/publish-and-test.yml:
--------------------------------------------------------------------------------

```yaml
name: Publish and Test (Tags)

on:
  push:
    tags:
      - 'v*.*.*'
  workflow_dispatch:

jobs:
  test-uvx-compatibility:
    runs-on: ubuntu-latest
    name: Test uvx compatibility
    
    steps:
    - name: Checkout repository
      uses: actions/checkout@v4

    - name: Set up Python
      uses: actions/setup-python@v4
      with:
        python-version: '3.11'

    - name: Install uv
      run: |
        curl -LsSf https://astral.sh/uv/install.sh | sh
        source $HOME/.cargo/env

    - name: Install package locally
      run: |
        source $HOME/.cargo/env
        uv pip install --system -e .

    - name: Test entry point
      run: |
        python -c "import mcp_memory_service.server; print('✓ Package can be imported')"
        python -m mcp_memory_service.server --version

    - name: Test uvx functionality
      run: |
        source $HOME/.cargo/env
        # uvx is now part of uv itself, no separate installation needed
        uv --version
        
        # Build wheel for uvx testing
        uv build
        
        # Test if uvx command is available
        which uvx || echo "uvx command provided by uv"
        
        # Test package structure compatibility
        echo "✓ Package structure compatible with uvx"

  test-docker-build:
    runs-on: ubuntu-latest
    name: Test Docker build
    
    steps:
    - name: Checkout repository
      uses: actions/checkout@v4

    - name: Set up Docker Buildx
      uses: docker/setup-buildx-action@v3

    - name: Debug - Check required files
      run: |
        echo "=== Checking required files for Docker build ==="
        echo "Dockerfile exists:" && ls -la tools/docker/Dockerfile
        echo "Source directory exists:" && ls -la src/
        echo "Entrypoint scripts exist:" && ls -la tools/docker/docker-entrypoint*.sh
        echo "Utils scripts exist:" && ls -la scripts/utils/
        echo "pyproject.toml exists:" && ls -la pyproject.toml
        echo "uv.lock exists:" && ls -la uv.lock

    - name: Build Docker image
      uses: docker/build-push-action@v5
      with:
        context: .
        file: ./tools/docker/Dockerfile
        platforms: linux/amd64
        push: false
        load: true
        tags: mcp-memory-service:test
        cache-from: type=gha
        cache-to: type=gha,mode=max
        build-args: |
          SKIP_MODEL_DOWNLOAD=true

    - name: Test Docker image
      run: |
        # Test image can be created (override entrypoint to run python directly)
        docker run --rm --entrypoint="" mcp-memory-service:test python -c "print('✓ Docker image works')"
        
        # Test that the server can show help
        docker run --rm mcp-memory-service:test --help > /dev/null && echo "✓ Server help works"

  publish-docker:
    needs: [test-uvx-compatibility, test-docker-build]
    runs-on: ubuntu-latest
    name: Publish Docker image
    if: github.event_name != 'pull_request'
    permissions:
      contents: read
      packages: write
      id-token: write
    
    steps:
    - name: Checkout repository
      uses: actions/checkout@v4

    - name: Set up Docker Buildx
      uses: docker/setup-buildx-action@v3

    - name: Debug - Check required files for GHCR build
      run: |
        echo "=== Checking required files for GHCR Docker build ==="
        echo "Dockerfile exists:" && ls -la tools/docker/Dockerfile
        echo "Source directory exists:" && ls -la src/
        echo "Entrypoint scripts exist:" && ls -la tools/docker/docker-entrypoint*.sh
        echo "Utils scripts exist:" && ls -la scripts/utils/
        echo "pyproject.toml exists:" && ls -la pyproject.toml
        echo "uv.lock exists:" && ls -la uv.lock

    - name: Log in to GitHub Container Registry
      uses: docker/login-action@v3
      with:
        registry: ghcr.io
        username: ${{ github.actor }}
        password: ${{ secrets.GITHUB_TOKEN }}

    - name: Extract metadata
      id: meta
      uses: docker/metadata-action@v5
      with:
        images: ghcr.io/doobidoo/mcp-memory-service
        tags: |
          type=ref,event=branch
          type=semver,pattern={{version}}
          type=semver,pattern={{major}}.{{minor}}
          type=semver,pattern={{major}}
          type=raw,value=latest,enable={{is_default_branch}}

    - name: Build and push Docker image
      uses: docker/build-push-action@v5
      with:
        context: .
        file: ./tools/docker/Dockerfile
        platforms: linux/amd64,linux/arm64
        push: true
        tags: ${{ steps.meta.outputs.tags }}
        labels: ${{ steps.meta.outputs.labels }}
        cache-from: type=gha
        cache-to: type=gha,mode=max
        build-args: |
          SKIP_MODEL_DOWNLOAD=true
        outputs: type=registry

  publish-pypi:
    needs: [test-uvx-compatibility, test-docker-build]
    runs-on: ubuntu-latest
    name: Publish to PyPI
    if: github.event_name != 'pull_request'
    permissions:
      id-token: write
      contents: read

    steps:
    - name: Checkout repository
      uses: actions/checkout@v4

    - name: Set up Python
      uses: actions/setup-python@v4
      with:
        python-version: '3.11'

    - name: Install build dependencies
      run: |
        python -m pip install --upgrade pip
        python -m pip install build twine

    - name: Build package
      run: python -m build

    - name: Publish to PyPI
      env:
        TWINE_USERNAME: __token__
        TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }}
      run: |
        twine upload dist/*

  update-documentation:
    needs: [publish-docker, publish-pypi]
    runs-on: ubuntu-latest
    name: Update documentation
    if: github.event_name != 'pull_request'
    
    steps:
    - name: Checkout repository
      uses: actions/checkout@v4

    - name: Update README with GitHub Container Registry info
      run: |
        echo "Docker image published successfully!" >> docker-publish.log
        echo "Available at: ghcr.io/doobidoo/mcp-memory-service" >> docker-publish.log

    - name: Create/update installation docs
      run: |
        mkdir -p docs/installation
        cat > docs/installation/github-container-registry.md << 'EOF'
        # GitHub Container Registry Installation
        
        The MCP Memory Service is now available on GitHub Container Registry for easy installation.
        
        ## Quick Start
        
        ```bash
        # Pull the latest image
        docker pull ghcr.io/doobidoo/mcp-memory-service:latest
        
        # Run with default settings
        docker run -d -p 8000:8000 \
          -v $(pwd)/data/chroma_db:/app/chroma_db \
          -v $(pwd)/data/backups:/app/backups \
          ghcr.io/doobidoo/mcp-memory-service:latest
        
        # Run in standalone mode
        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 \
          ghcr.io/doobidoo/mcp-memory-service:latest
        ```
        
        ## Available Tags
        
        - `latest` - Latest stable release
        - `main` - Latest development version
        - `v*.*.*` - Specific version tags
        
        ## uvx Installation
        
        You can also install using uvx (included with uv):
        
        ```bash
        # Install uv if not already installed
        pip install uv
        # Or use the installer script:
        # curl -LsSf https://astral.sh/uv/install.sh | sh
        
        # Install and run the memory service with uvx
        uvx mcp-memory-service
        ```
        EOF
```

--------------------------------------------------------------------------------
/docs/research/code-execution-interface-summary.md:
--------------------------------------------------------------------------------

```markdown
# Code Execution Interface - Executive Summary
## Issue #206 Implementation Guide

**TL;DR:** Implement Python code API to reduce token consumption by 90-95% while maintaining full backward compatibility. Start with session hooks (75% reduction, 109M+ tokens saved annually).

---

## The Problem

Current MCP tool-based architecture consumes excessive tokens:
- **Session hooks:** 3,600-9,600 tokens per session start
- **Search operations:** 2,625 tokens for 5 results
- **Document ingestion:** 57,400 tokens for 50 PDFs
- **Annual waste:** 17-379 million tokens across user base

## The Solution

Replace verbose MCP tool calls with direct Python code execution:

```python
# Before (625 tokens)
result = await mcp.call_tool('retrieve_memory', {
    'query': 'architecture decisions',
    'limit': 5,
    'similarity_threshold': 0.7
})

# After (25 tokens)
from mcp_memory_service.api import search
results = search('architecture decisions', limit=5)
```

## Key Components

### 1. Compact Data Types (91% size reduction)

```python
# CompactMemory: 73 tokens vs 820 tokens for full Memory
class CompactMemory(NamedTuple):
    hash: str           # 8-char hash
    preview: str        # First 200 chars
    tags: tuple[str]    # Immutable tags
    created: float      # Unix timestamp
    score: float        # Relevance score
```

### 2. Simple API Functions

```python
from mcp_memory_service.api import search, store, health

# Search (20 tokens)
results = search("query", limit=5)

# Store (15 tokens)
hash = store("content", tags=['note'])

# Health (5 tokens)
info = health()
```

### 3. Hook Integration

```javascript
// Node.js hook with fallback
try {
    // Code execution (fast, efficient)
    const output = execSync('python -c "from mcp_memory_service.api import search; ..."');
    memories = parseCompactResults(output);
} catch (error) {
    // Fallback to MCP tools
    memories = await mcpClient.retrieve_memory({...});
}
```

## Expected Impact

| Metric | Current | Target | Improvement |
|--------|---------|--------|-------------|
| Session hooks | 3,600-9,600 tokens | 900-2,400 | **75% reduction** |
| Search (5 results) | 2,625 tokens | 385 | **85% reduction** |
| Store memory | 150 tokens | 15 | **90% reduction** |
| Annual savings (10 users) | - | 109.5M tokens | **$16.43/year** |
| Annual savings (100 users) | - | 2.19B tokens | **$328.50/year** |

## Implementation Timeline

```
Week 1-2: Core Infrastructure
├─ Compact types (CompactMemory, CompactSearchResult)
├─ API functions (search, store, health)
├─ Tests and benchmarks
└─ Documentation

Week 3: Session Hook Migration (HIGHEST PRIORITY)
├─ Update session-start.js
├─ Add fallback mechanism
├─ Validate 75% reduction
└─ Deploy to beta

Week 4-5: Search Operations
├─ Mid-conversation hooks
├─ Topic-change hooks
└─ Document best practices

Week 6+: Polish & Extensions
```

## Technical Architecture

### Filesystem Structure
```
src/mcp_memory_service/
├── api/                    # NEW: Code execution interface
│   ├── __init__.py        # Public API exports
│   ├── compact.py         # Compact result types
│   ├── search.py          # Search operations
│   ├── storage.py         # Storage operations
│   └── utils.py           # Utilities
├── models/
│   └── compact.py         # NEW: CompactMemory types
└── server.py              # EXISTING: MCP server (unchanged)
```

### Key Design Decisions

1. **NamedTuple for Compact Types**
   - ✅ Fast (C-based), immutable, type-safe
   - ✅ 60-90% size reduction
   - ✅ Clear field names

2. **Sync Wrappers**
   - ✅ Hide asyncio complexity
   - ✅ Connection reuse
   - ✅ <10ms overhead

3. **Backward Compatibility**
   - ✅ MCP tools continue working
   - ✅ Gradual opt-in migration
   - ✅ Zero breaking changes

## Validation from Research

### Industry Alignment
- ✅ **Anthropic (Nov 2025):** Official MCP code execution announcement
- ✅ **CodeAgents Framework:** 70%+ token reduction demonstrated
- ✅ **mcp-python-interpreter:** Proven code execution patterns

### Performance Benchmarks
- ✅ **NamedTuple:** 8% faster creation, fastest access
- ✅ **Compact types:** 85-91% token reduction measured
- ✅ **Real-world savings:** 109M+ tokens annually (conservative)

## Risk Assessment

| Risk | Severity | Mitigation |
|------|----------|------------|
| Breaking changes | HIGH | Parallel operation, fallback mechanism |
| Performance degradation | MEDIUM | Benchmarks show <5ms overhead |
| Async/sync mismatch | LOW | Sync wrappers with asyncio.run() |
| Connection management | LOW | Global instance with reuse |
| Error handling | LOW | Expand function for debugging |

**Overall Risk:** LOW - Incremental approach with proven patterns

## Success Criteria

### Phase 1 (Core Infrastructure)
- ✅ API functions work in sync context
- ✅ Token reduction ≥85% measured
- ✅ Performance overhead <5ms
- ✅ Unit tests ≥90% coverage

### Phase 2 (Session Hooks)
- ✅ Token reduction ≥75% in production
- ✅ Hook execution <500ms
- ✅ Fallback mechanism validates
- ✅ Zero user-reported issues

### Phase 3 (Search Operations)
- ✅ Token reduction ≥90%
- ✅ Migration guide complete
- ✅ Community feedback positive

## Next Steps

### Immediate Actions (This Week)
1. Create `src/mcp_memory_service/api/` directory structure
2. Implement `CompactMemory` and `CompactSearchResult` types
3. Write `search()`, `store()`, `health()` functions
4. Add unit tests with token benchmarks

### Priority Tasks
1. **Session hook migration** - Highest impact (3,600 → 900 tokens)
2. **Documentation** - API reference with examples
3. **Beta testing** - Validate with real users
4. **Metrics collection** - Measure actual token savings

## Recommended Reading

### Full Research Document
- `docs/research/code-execution-interface-implementation.md`
  - Comprehensive analysis (10,000+ words)
  - Detailed code examples
  - Industry research findings
  - Complete implementation guide

### Key Sections
1. **Architecture Recommendations** (Section 3)
2. **Implementation Examples** (Section 4)
3. **Migration Approach** (Section 7)
4. **Success Metrics** (Section 8)

---

## Quick Reference

### Token Savings Calculator

```python
# Current MCP approach
tool_schema = 125 tokens
full_memory = 820 tokens per result
total = tool_schema + (full_memory * num_results)

# Example: 5 results
current = 125 + (820 * 5) = 4,225 tokens

# Code execution approach
import_cost = 10 tokens (once)
compact_memory = 73 tokens per result
total = import_cost + (compact_memory * num_results)

# Example: 5 results
new = 10 + (73 * 5) = 375 tokens

# Reduction
reduction = (4225 - 375) / 4225 * 100 = 91.1%
```

### Common Patterns

```python
# Pattern 1: Simple search
from mcp_memory_service.api import search
results = search("query", limit=5)
for m in results.memories:
    print(f"{m.hash}: {m.preview[:50]}")

# Pattern 2: Tag filtering
from mcp_memory_service.api import search_by_tag
results = search_by_tag(['architecture', 'decision'], limit=10)

# Pattern 3: Store with fallback
from mcp_memory_service.api import store
try:
    hash = store("content", tags=['note'])
    print(f"Stored: {hash}")
except Exception as e:
    # Fallback to MCP tool
    await mcp_client.store_memory({...})

# Pattern 4: Health check
from mcp_memory_service.api import health
info = health()
if info.ready:
    print(f"Backend: {info.backend}, Count: {info.count}")
```

---

**Document Version:** 1.0
**Last Updated:** November 6, 2025
**Status:** Ready for Implementation
**Estimated Effort:** 2-3 weeks (Phase 1-2)
**ROI:** 109M+ tokens saved annually (conservative)

```

--------------------------------------------------------------------------------
/scripts/pr/quality_gate.sh:
--------------------------------------------------------------------------------

```bash
#!/bin/bash
# scripts/pr/quality_gate.sh - Run all quality checks before PR review
#
# Usage: bash scripts/pr/quality_gate.sh <PR_NUMBER> [--with-pyscn]
# Example: bash scripts/pr/quality_gate.sh 123
# Example: bash scripts/pr/quality_gate.sh 123 --with-pyscn  # Comprehensive analysis

set -e

PR_NUMBER=$1
RUN_PYSCN=false

# Parse arguments
shift  # Remove PR_NUMBER from arguments
while [[ $# -gt 0 ]]; do
    case $1 in
        --with-pyscn)
            RUN_PYSCN=true
            shift
            ;;
        *)
            echo "Unknown option: $1"
            echo "Usage: $0 <PR_NUMBER> [--with-pyscn]"
            exit 1
            ;;
    esac
done

if [ -z "$PR_NUMBER" ]; then
    echo "Usage: $0 <PR_NUMBER> [--with-pyscn]"
    exit 1
fi

if ! command -v gh &> /dev/null; then
    echo "Error: GitHub CLI (gh) is not installed"
    exit 1
fi

if ! command -v gemini &> /dev/null; then
    echo "Error: Gemini CLI is not installed"
    exit 1
fi

echo "=== PR Quality Gate for #$PR_NUMBER ==="
echo ""

exit_code=0
warnings=()
critical_issues=()

# Get changed Python files
echo "Fetching changed files..."
changed_files=$(gh pr diff $PR_NUMBER --name-only | grep '\.py$' || echo "")

if [ -z "$changed_files" ]; then
    echo "No Python files changed in this PR."
    exit 0
fi

echo "Changed Python files:"
echo "$changed_files"
echo ""

# Check 1: Code complexity
echo "=== Check 1: Code Complexity ==="
echo "$changed_files" | while IFS= read -r file; do
    if [ -z "$file" ]; then
        continue
    fi

    if [ ! -f "$file" ]; then
        echo "Skipping $file (file not found in working directory)"
        continue
    fi

    echo "Analyzing: $file"
    result=$(gemini "Analyze code complexity. Rate each function 1-10 (1=simple, 10=very complex). Report ONLY functions with score >7 in format 'FunctionName: Score X - Reason'. File content:

$(cat "$file")" 2>&1 || echo "")

    if echo "$result" | grep -qi "score [89]\|score 10"; then
        warnings+=("High complexity in $file: $result")
        exit_code=1
    fi
done
echo ""

# Check 2: Security scan
echo "=== Check 2: Security Vulnerabilities ==="
echo "$changed_files" | while IFS= read -r file; do
    if [ -z "$file" ]; then
        continue
    fi

    if [ ! -f "$file" ]; then
        continue
    fi

    echo "Scanning: $file"
    # Request machine-parseable output (similar to pre-commit hook)
    result=$(gemini "Security audit. Check for: SQL injection (raw SQL), XSS (unescaped HTML), command injection (os.system, subprocess with shell=True), path traversal, hardcoded secrets.

IMPORTANT: Output format:
- If ANY vulnerability found, start response with: VULNERABILITY_DETECTED: [type]
- If NO vulnerabilities found, start response with: SECURITY_CLEAN
- Then provide details

File content:
$(cat "$file")" 2>&1 || echo "SECURITY_CLEAN")

    # Check for machine-parseable vulnerability marker (more reliable than grep)
    if echo "$result" | grep -q "^VULNERABILITY_DETECTED:"; then
        critical_issues+=("🔴 Security issue in $file: $result")
        exit_code=2
    fi
done
echo ""

# Check 3: Test coverage
echo "=== Check 3: Test Coverage ==="
test_files=$(gh pr diff $PR_NUMBER --name-only | grep -c '^tests/.*\.py$' || echo "0")
# Count code files directly from changed_files
code_files=$(echo "$changed_files" | grep -c '\.py$' || echo "0")

if [ $code_files -gt 0 ] && [ $test_files -eq 0 ]; then
    warnings+=("No test files added/modified despite $code_files code file(s) changed")
    if [ $exit_code -eq 0 ]; then
        exit_code=1
    fi
fi
echo "Code files changed: $code_files"
echo "Test files changed: $test_files"
echo ""

# Check 4: Breaking changes
echo "=== Check 4: Breaking Changes ==="
head_branch=$(gh pr view $PR_NUMBER --json headRefName --jq '.headRefName')

# Get API-related changes
api_changes=$(git diff origin/main...origin/$head_branch -- \
    src/mcp_memory_service/tools.py \
    src/mcp_memory_service/web/api/ \
    2>/dev/null || echo "")

if [ ! -z "$api_changes" ]; then
    echo "Analyzing API changes..."
    # Truncate to 200 lines (increased from 100) to capture more context while preventing overflow
    # Note: Large PRs may still lose context, but this is a reasonable trade-off for performance
    breaking_result=$(gemini "Analyze for breaking changes. Breaking changes include: removed functions/endpoints, changed signatures (parameters removed/reordered), changed return types, renamed public APIs, changed HTTP paths/methods. Report ONLY if breaking changes found with severity (CRITICAL/HIGH/MEDIUM). Changes:

$(echo "$api_changes" | head -200)" 2>&1 || echo "")

    if echo "$breaking_result" | grep -qi "breaking\|CRITICAL\|HIGH"; then
        warnings+=("⚠️  Potential breaking changes detected: $breaking_result")
        if [ $exit_code -eq 0 ]; then
            exit_code=1
        fi
    fi
else
    echo "No API changes detected"
fi
echo ""

# Check 5: pyscn comprehensive analysis (optional)
if [ "$RUN_PYSCN" = true ]; then
    echo "=== Check 5: pyscn Comprehensive Analysis ==="

    if command -v pyscn &> /dev/null; then
        echo "Running pyscn static analysis..."

        # Run pyscn analysis (will post comment if successful)
        if bash scripts/pr/run_pyscn_analysis.sh --pr $PR_NUMBER --threshold 50; then
            echo "✅ pyscn analysis passed"
        else
            echo "⚠️  pyscn analysis found quality issues"
            # Note: Don't block on pyscn failures (informational only for now)
            # exit_code can be set to 1 here if you want to block on pyscn failures
        fi
    else
        echo "⚠️  pyscn not installed, skipping comprehensive analysis"
        echo "Install with: pip install pyscn"
    fi
    echo ""
fi

# Report results
echo "=== Quality Gate Summary ==="
echo ""

if [ $exit_code -eq 0 ]; then
    echo "✅ ALL CHECKS PASSED"
    echo ""
    echo "Quality Gate Results:"
    echo "- Code complexity: ✅ OK"
    echo "- Security scan: ✅ OK"
    echo "- Test coverage: ✅ OK"
    echo "- Breaking changes: ✅ None detected"
    if [ "$RUN_PYSCN" = true ]; then
        echo "- pyscn analysis: ✅ OK (see separate comment)"
    fi
    echo ""

    pyscn_note=""
    if [ "$RUN_PYSCN" = true ]; then
        pyscn_note="
- ✅ pyscn comprehensive analysis: See detailed report comment"
    fi

    gh pr comment $PR_NUMBER --body "✅ **Quality Gate PASSED**

All automated checks completed successfully:
- ✅ Code complexity: OK
- ✅ Security scan: OK
- ✅ Test coverage: OK
- ✅ Breaking changes: None detected${pyscn_note}

PR is ready for Gemini review."

elif [ $exit_code -eq 2 ]; then
    echo "🔴 CRITICAL FAILURES"
    echo ""
    for issue in "${critical_issues[@]}"; do
        echo "$issue"
    done
    echo ""

    # Format issues for comment
    issues_md=$(printf '%s\n' "${critical_issues[@]}" | sed 's/^/- /')

    gh pr comment $PR_NUMBER --body "🔴 **Quality Gate FAILED - CRITICAL**

Security vulnerabilities detected. PR is blocked until issues are resolved.

$issues_md

**Action Required:**
Run \`bash scripts/security/scan_vulnerabilities.sh\` locally and fix all security issues before proceeding."

else
    echo "⚠️  WARNINGS (non-blocking)"
    echo ""
    for warning in "${warnings[@]}"; do
        echo "- $warning"
    done
    echo ""

    # Format warnings for comment
    warnings_md=$(printf '%s\n' "${warnings[@]}" | sed 's/^/- /')

    gh pr comment $PR_NUMBER --body "⚠️ **Quality Gate WARNINGS**

Some checks require attention (non-blocking):

$warnings_md

**Recommendation:**
Consider addressing these issues before requesting review to improve code quality."

fi

exit $exit_code

```

--------------------------------------------------------------------------------
/docs/enhancement-roadmap-issue-14.md:
--------------------------------------------------------------------------------

```markdown
# Memory Awareness Enhancement Roadmap - Issue #14

## Executive Summary

This roadmap outlines the transformation of GitHub issue #14 from a basic external utility to a sophisticated memory-aware Claude Code experience leveraging advanced features like hooks, project awareness, and MCP deep integration.

## Phase 1: Automatic Memory Awareness (Weeks 1-2)

### 1.1 Session Startup Hooks
**Goal**: Automatically inject relevant memories when starting a Claude Code session

**Implementation**:
```javascript
// claude-hooks/session-start.js
export async function onSessionStart(context) {
  const projectContext = await detectProjectContext(context.workingDirectory);
  const relevantMemories = await queryMemoryService({
    tags: [projectContext.name, 'key-decisions', 'recent-insights'],
    timeRange: 'last-2-weeks',
    limit: 8
  });
  
  if (relevantMemories.length > 0) {
    await injectSystemMessage(`
      Recent project context from memory:
      ${formatMemoriesForContext(relevantMemories)}
    `);
  }
}
```

**Features**:
- Project detection based on git repository and directory structure
- Smart memory filtering by project relevance and recency
- Automatic context injection without user intervention

### 1.2 Project-Aware Memory Selection
**Goal**: Intelligently select memories based on current project context

**Implementation**:
```python
# Enhanced memory retrieval with project awareness
class ProjectAwareMemoryRetrieval:
    def select_relevant_memories(self, project_context):
        # Score memories by relevance to current project
        memories = self.memory_service.search_by_tags([
            project_context.name,
            f"tech:{project_context.language}",
            "decisions", "architecture", "bugs-fixed"
        ])
        
        # Apply relevance scoring
        scored_memories = self.score_by_relevance(memories, project_context)
        return scored_memories[:10]
```

### 1.3 Conversation Context Injection
**Goal**: Seamlessly inject memory context into conversation flow

**Deliverables**:
- Session initialization hooks
- Project context detection algorithm
- Memory relevance scoring system
- Context formatting and injection utilities

## Phase 2: Intelligent Context Updates (Weeks 3-4)

### 2.1 Dynamic Memory Loading
**Goal**: Update memory context as conversation topics evolve

**Implementation**:
```javascript
// claude-hooks/topic-change.js
export async function onTopicChange(context, newTopics) {
  const additionalMemories = await queryMemoryService({
    semanticSearch: newTopics,
    excludeAlreadyLoaded: context.loadedMemoryHashes,
    limit: 5
  });
  
  if (additionalMemories.length > 0) {
    await updateContext(`
      Additional relevant context:
      ${formatMemoriesForContext(additionalMemories)}
    `);
  }
}
```

### 2.2 Conversation Continuity
**Goal**: Link conversations across sessions for seamless continuity

**Features**:
- Cross-session conversation linking
- Session outcome consolidation
- Persistent conversation threads

### 2.3 Smart Memory Filtering
**Goal**: AI-powered memory selection based on conversation analysis

**Implementation**:
- Natural language processing for topic extraction
- Semantic similarity matching
- Relevance decay algorithms
- User preference learning

## Phase 3: Advanced Integration Features (Weeks 5-6)

### 3.1 Auto-Tagging Conversations
**Goal**: Automatically categorize and tag conversation outcomes

**Implementation**:
```javascript
// claude-hooks/session-end.js
export async function onSessionEnd(context) {
  const sessionSummary = await analyzeSession(context.conversation);
  const autoTags = await generateTags(sessionSummary);
  
  await storeMemory({
    content: sessionSummary,
    tags: [...autoTags, 'session-outcome', context.project.name],
    type: 'session-summary'
  });
}
```

### 3.2 Memory Consolidation System
**Goal**: Intelligent organization of session insights and outcomes

**Features**:
- Duplicate detection and merging
- Insight extraction and categorization
- Knowledge graph building
- Memory lifecycle management

### 3.3 Cross-Session Intelligence
**Goal**: Maintain knowledge continuity across different coding sessions

**Implementation**:
- Session relationship mapping
- Progressive memory building
- Context evolution tracking
- Learning pattern recognition

## Technical Architecture

### Core Components

1. **Memory Hook System**
   - Session lifecycle hooks
   - Project context detection
   - Dynamic memory injection

2. **Intelligent Memory Selection**
   - Relevance scoring algorithms
   - Topic analysis and matching
   - Context-aware filtering

3. **Context Management**
   - Dynamic context updates
   - Memory formatting utilities
   - Conversation continuity tracking

4. **Integration Layer**
   - Claude Code hooks interface
   - MCP Memory Service connector
   - Project structure analysis

### API Enhancements

```python
# New memory service endpoints for Claude Code integration
@app.post("/claude-code/session-context")
async def get_session_context(project: ProjectContext):
    """Get relevant memories for Claude Code session initialization."""
    
@app.post("/claude-code/dynamic-context")  
async def get_dynamic_context(topics: List[str], exclude: List[str]):
    """Get additional context based on evolving conversation topics."""
    
@app.post("/claude-code/consolidate-session")
async def consolidate_session(session_data: SessionData):
    """Store and organize session outcomes with intelligent tagging."""
```

## Success Metrics

### Phase 1 Targets
- ✅ 100% automatic session context injection
- ✅ <2 second session startup time with memory loading
- ✅ 90%+ relevant memory selection accuracy

### Phase 2 Targets  
- ✅ Real-time context updates based on conversation flow
- ✅ 95%+ conversation continuity across sessions
- ✅ Intelligent topic detection and memory matching

### Phase 3 Targets
- ✅ Fully autonomous memory management
- ✅ Cross-session knowledge building
- ✅ Adaptive learning from user interactions

## Implementation Priority

**High Priority (Phase 1)**:
1. Session startup hooks for automatic memory injection
2. Project-aware memory selection algorithms
3. Basic context injection utilities

**Medium Priority (Phase 2)**:
1. Dynamic memory loading based on conversation topics
2. Cross-session conversation linking
3. Smart memory filtering enhancements

**Enhancement Priority (Phase 3)**:
1. Auto-tagging and session outcome consolidation
2. Advanced memory organization systems
3. Machine learning-based relevance optimization

## Risk Mitigation

### Technical Risks
- **Performance Impact**: Implement lazy loading and caching strategies
- **Context Overload**: Smart filtering and relevance-based selection  
- **Memory Service Availability**: Graceful degradation without memory service

### User Experience Risks
- **Information Overload**: Configurable memory injection levels
- **Privacy Concerns**: Clear memory access controls and user preferences
- **Learning Curve**: Seamless integration with minimal configuration required

## Conclusion

This enhancement transforms issue #14 from a basic utility into a revolutionary memory-aware Claude Code experience. By leveraging Claude Code's advanced features, we can deliver the original vision of automatic memory context injection while providing intelligent, context-aware assistance that learns and adapts to user patterns.

The phased approach ensures incremental value delivery while building towards a sophisticated memory-aware development environment that fundamentally changes how developers interact with their code and project knowledge.
```

--------------------------------------------------------------------------------
/scripts/maintenance/cleanup_organize.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.

"""
MCP-MEMORY-SERVICE Cleanup and Organization Script

This script implements the cleanup plan documented in CLEANUP_PLAN.md.
It creates the necessary directory structure, moves files to their new locations,
and prepares everything for committing to the new branch.
"""

import os
import sys
import shutil
from pathlib import Path
import subprocess
import datetime

def run_command(command):
    """Run a shell command and print the result."""
    print(f"Running: {command}")
    result = subprocess.run(command, shell=True, capture_output=True, text=True)
    if result.returncode != 0:
        print(f"ERROR: {result.stderr}")
        return False
    print(f"SUCCESS: {result.stdout}")
    return True

def create_directory(path):
    """Create a directory if it doesn't exist."""
    if not os.path.exists(path):
        print(f"Creating directory: {path}")
        os.makedirs(path)
    else:
        print(f"Directory already exists: {path}")

def move_file(src, dest):
    """Move a file from src to dest, creating destination directory if needed."""
    dest_dir = os.path.dirname(dest)
    # Only try to create the directory if dest_dir is not empty
    if dest_dir and not os.path.exists(dest_dir):
        os.makedirs(dest_dir)
    
    if os.path.exists(src):
        print(f"Moving {src} to {dest}")
        shutil.move(src, dest)
    else:
        print(f"WARNING: Source file does not exist: {src}")

def copy_file(src, dest):
    """Copy a file from src to dest, creating destination directory if needed."""
    dest_dir = os.path.dirname(dest)
    # Only try to create the directory if dest_dir is not empty
    if dest_dir and not os.path.exists(dest_dir):
        os.makedirs(dest_dir)
    
    if os.path.exists(src):
        print(f"Copying {src} to {dest}")
        shutil.copy2(src, dest)
    else:
        print(f"WARNING: Source file does not exist: {src}")

def create_readme(path, content):
    """Create a README.md file with the given content."""
    with open(path, 'w') as f:
        f.write(content)
    print(f"Created README: {path}")

def main():
    # Change to the repository root directory
    repo_root = os.getcwd()
    print(f"Working in repository root: {repo_root}")
    
    # 1. Create test directory structure
    test_dirs = [
        "tests/integration",
        "tests/unit",
        "tests/performance"
    ]
    for directory in test_dirs:
        create_directory(directory)
    
    # 2. Create documentation directory structure
    doc_dirs = [
        "docs/guides",
        "docs/implementation",
        "docs/api",
        "docs/examples"
    ]
    for directory in doc_dirs:
        create_directory(directory)
    
    # 3. Create archive directory
    today = datetime.date.today().strftime("%Y-%m-%d")
    archive_dir = f"archive/{today}"
    create_directory(archive_dir)
    
    # 4. Move test files
    test_files = [
        ("test_chromadb.py", "tests/unit/test_chroma.py"),
        ("test_health_check_fixes.py", "tests/integration/test_storage.py"),
        ("test_issue_5_fix.py", "tests/unit/test_tags.py"),
        ("test_performance_optimizations.py", "tests/performance/test_caching.py")
    ]
    for src, dest in test_files:
        move_file(src, dest)
    
    # 5. Move documentation files
    doc_files = [
        ("HEALTH_CHECK_FIXES_SUMMARY.md", "docs/implementation/health_checks.md"),
        ("PERFORMANCE_OPTIMIZATION_SUMMARY.md", "docs/implementation/performance.md"),
        ("CLAUDE.md", "docs/guides/claude_integration.md")
    ]
    for src, dest in doc_files:
        move_file(src, dest)
    
    # 6. Archive backup files
    archive_files = [
        ("backup_performance_optimization", f"{archive_dir}/backup_performance_optimization")
    ]
    for src, dest in archive_files:
        if os.path.exists(src):
            if os.path.exists(dest):
                print(f"Archive destination already exists: {dest}")
            else:
                shutil.copytree(src, dest)
                print(f"Archived {src} to {dest}")
        else:
            print(f"WARNING: Source directory does not exist: {src}")
    
    # 7. Update CHANGELOG.md
    if os.path.exists("CHANGELOG.md.new"):
        move_file("CHANGELOG.md.new", "CHANGELOG.md")
    
    # 8. Create test README files
    test_readme = """# MCP-MEMORY-SERVICE Tests

This directory contains tests for the MCP-MEMORY-SERVICE project.

## Directory Structure

- `integration/` - Integration tests between components
- `unit/` - Unit tests for individual components
- `performance/` - Performance benchmarks

## Running Tests

```bash
# Run all tests
pytest

# Run specific test category
pytest tests/unit/
pytest tests/integration/
pytest tests/performance/
```
"""
    create_readme("tests/README.md", test_readme)
    
    # 9. Create docs README file
    docs_readme = """# MCP-MEMORY-SERVICE Documentation

This directory contains documentation for the MCP-MEMORY-SERVICE project.

## Directory Structure

- `guides/` - User guides and tutorials
- `implementation/` - Implementation details and technical documentation
- `api/` - API reference documentation
- `examples/` - Example code and usage patterns
"""
    create_readme("docs/README.md", docs_readme)
    
    # 10. Create archive README file
    archive_readme = f"""# Archive Directory

This directory contains archived files from previous versions of MCP-MEMORY-SERVICE.

## {today}/

- `backup_performance_optimization/` - Backup files from performance optimization work
"""
    create_readme(f"{archive_dir}/README.md", archive_readme)
    
    # 11. Create pytest.ini
    pytest_ini = """[pytest]
testpaths = tests
python_files = test_*.py
python_classes = Test*
python_functions = test_*
markers =
    unit: unit tests
    integration: integration tests
    performance: performance tests
"""
    with open("pytest.ini", 'w') as f:
        f.write(pytest_ini)
    print("Created pytest.ini")
    
    # 12. Create conftest.py
    conftest = """import pytest
import os
import sys
import tempfile
import shutil

# Add src directory to Python path
sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'src'))

@pytest.fixture
def temp_db_path():
    '''Create a temporary directory for ChromaDB testing.'''
    temp_dir = tempfile.mkdtemp()
    yield temp_dir
    # Clean up after test
    shutil.rmtree(temp_dir)
"""
    with open("tests/conftest.py", 'w') as f:
        f.write(conftest)
    print("Created tests/conftest.py")
    
    print("\nCleanup and organization completed!")
    print("Next steps:")
    print("1. Verify all files are in their correct locations")
    print("2. Run tests to ensure everything still works")
    print("3. Create a new git branch and commit the changes")
    print("   git checkout -b feature/cleanup-and-organization")
    print("   git add .")
    print("   git commit -m \"Organize tests, documentation, and archive old files\"")
    print("4. Push the branch for hardware testing")
    print("   git push origin feature/cleanup-and-organization")

if __name__ == "__main__":
    main()

```

--------------------------------------------------------------------------------
/archive/docs-removed-2025-08-23/complete-setup-guide.md:
--------------------------------------------------------------------------------

```markdown
# MCP Memory Service - Complete Setup Guide

## ✅ Successfully Configured Features

### 🧠 **Consolidation System**
- **Exponential Decay**: Memory aging with retention periods
- **Creative Associations**: Auto-discovery of memory connections  
- **Semantic Clustering**: DBSCAN algorithm grouping
- **Memory Compression**: 500-char summaries with originals preserved
- **Controlled Forgetting**: Relevance-based archival
- **Automated Scheduling**: Daily/weekly/monthly runs

### 🌐 **mDNS Multi-Client HTTPS**
- **Service Name**: `memory.local` (clean, no port needed)
- **Service Type**: `_http._tcp.local.` (standard HTTP service)
- **Port**: 443 (standard HTTPS)
- **Auto-Discovery**: Zero-configuration client setup
- **HTTPS**: Self-signed certificates (auto-generated)
- **Multi-Interface**: Available on all network interfaces
- **Real-time Updates**: Server-Sent Events (SSE)
- **Security**: Non-root binding via CAP_NET_BIND_SERVICE

### 🚀 **Auto-Startup Service**
- **Systemd Integration**: Starts on boot automatically
- **Auto-Restart**: Recovers from failures
- **User Service**: Runs as regular user (not root)
- **Logging**: Integrated with systemd journal

## 📋 **Complete Installation Steps**

### **1. Initial Setup**
```bash
# Create virtual environment and install
python3 -m venv venv
source venv/bin/activate
python install.py --server-mode --enable-http-api
```

### **2. Configure Auto-Startup**
```bash
# Install systemd service
bash install_service.sh

# Update service configuration (fixed version)
./update_service.sh

# Start service
sudo systemctl start mcp-memory

# Verify it's running
sudo systemctl status mcp-memory
```

### **3. Configure Firewall**
```bash
# Allow mDNS discovery
sudo ufw allow 5353/udp

# Allow HTTPS server
sudo ufw allow 8000/tcp
```

## 🔧 **Service Configuration**

### **Environment Variables**
```bash
MCP_CONSOLIDATION_ENABLED=true
MCP_MDNS_ENABLED=true  
MCP_HTTPS_ENABLED=true
MCP_MDNS_SERVICE_NAME="memory"
MCP_HTTP_HOST=0.0.0.0
MCP_HTTP_PORT=8000
MCP_MEMORY_STORAGE_BACKEND=sqlite_vec
MCP_API_KEY=mcp-0b1ccbde2197a08dcb12d41af4044be6
```

### **Consolidation Settings**
- **Retention Periods**: Critical (365d), Reference (180d), Standard (30d), Temporary (7d)
- **Association Discovery**: Similarity range 0.3-0.7, max 100 pairs per run
- **Clustering**: DBSCAN algorithm, minimum 5 memories per cluster
- **Compression**: 500 character summaries, preserve originals
- **Forgetting**: Relevance threshold 0.1, 90-day access threshold
- **Schedule**: Daily 2AM, Weekly Sunday 3AM, Monthly 1st 4AM

## 🌐 **Access Points**

### **Local Access**
- **Dashboard**: https://localhost:443 or https://memory.local
- **API Documentation**: https://memory.local/api/docs  
- **Health Check**: https://memory.local/api/health
- **SSE Events**: https://memory.local/api/events
- **Connection Stats**: https://memory.local/api/events/stats

### **Network Access**
- **Clean mDNS**: https://memory.local (no port needed!)
- **mDNS Discovery**: `memory._http._tcp.local.`
- **Auto-Discovery**: Clients find service automatically
- **Standard Port**: 443 (HTTPS default)

## 🛠️ **Service Management**

### **Using 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
```

### **Direct systemctl Commands**
```bash
sudo systemctl start mcp-memory      # Start
sudo systemctl stop mcp-memory       # Stop
sudo systemctl restart mcp-memory    # Restart
sudo systemctl status mcp-memory     # Status
sudo systemctl enable mcp-memory     # Enable startup
sudo systemctl disable mcp-memory    # Disable startup
sudo journalctl -u mcp-memory -f     # Live logs
```

## 🔍 **Verification Tests**

### **1. Service Status**
```bash
sudo systemctl status mcp-memory
# Should show: Active: active (running)
```

### **2. API Health**  
```bash
curl -k https://localhost:8000/api/health
# Should return: {"status": "healthy", ...}
```

### **3. mDNS Discovery**
```bash
avahi-browse -t _mcp-memory._tcp
# Should show: memory on multiple interfaces
```

### **4. HTTPS Certificate**
```bash
openssl s_client -connect localhost:8000 -servername localhost < /dev/null
# Should show certificate details
```

## 📁 **File Structure**

### **Core Files**
- `mcp-memory.service` - Systemd service configuration
- `install_service.sh` - Service installation script
- `service_control.sh` - Service management script
- `update_service.sh` - Configuration update script
- `test_service.sh` - Debug testing script

### **Setup Scripts**  
- `setup_consolidation_mdns.sh` - Manual startup script
- `COMPLETE_SETUP_GUIDE.md` - This comprehensive guide
- `STARTUP_SETUP_GUIDE.md` - Original startup guide

## 🔐 **Security Configuration**

### **API Authentication**
- **API Key**: `mcp-0b1ccbde2197a08dcb12d41af4044be6`
- **HTTPS Only**: Self-signed certificates for development
- **Local Network**: mDNS discovery limited to local network

### **Systemd Security**
- **User Service**: Runs as `hkr` user (not root)
- **Working Directory**: `/home/hkr/repositories/mcp-memory-service`
- **No Privilege Escalation**: NoNewPrivileges removed for compatibility

## 🎯 **Client Configuration**

### **Claude Desktop Auto-Discovery**
```json
{
  "mcpServers": {
    "memory": {
      "command": "node",
      "args": ["/path/to/examples/http-mcp-bridge.js"],
      "env": {
        "MCP_MEMORY_AUTO_DISCOVER": "true",
        "MCP_MEMORY_PREFER_HTTPS": "true", 
        "MCP_MEMORY_API_KEY": "mcp-0b1ccbde2197a08dcb12d41af4044be6"
      }
    }
  }
}
```

### **Manual Connection**
```json
{
  "mcpServers": {
    "memory": {
      "command": "node", 
      "args": ["/path/to/examples/http-mcp-bridge.js"],
      "env": {
        "MCP_MEMORY_HTTP_ENDPOINT": "https://memory.local/api",
        "MCP_MEMORY_API_KEY": "mcp-0b1ccbde2197a08dcb12d41af4044be6"
      }
    }
  }
}
```

## 🚨 **Troubleshooting**

### **Service Won't Start**
```bash
# Check detailed logs
sudo journalctl -u mcp-memory --no-pager -n 50

# Test manual startup
./test_service.sh

# Verify virtual environment
ls -la venv/bin/python
```

### **Can't Connect to API**
```bash
# Check if service is listening
ss -tlnp | grep :443

# Test local connection
curl -k https://memory.local/api/health

# Check firewall
sudo ufw status
```

### **No mDNS Discovery**
```bash
# Test mDNS
avahi-browse -t _http._tcp | grep memory

# Test resolution
avahi-resolve-host-name memory.local

# Check network interfaces
ip addr show

# Verify multicast support
ping 224.0.0.251
```

### **Port 443 Conflicts (Pi-hole, etc.)**
```bash
# Check what's using port 443
sudo netstat -tlnp | grep :443

# Disable conflicting services (example: Pi-hole)
sudo systemctl stop pihole-FTL
sudo systemctl disable pihole-FTL
sudo systemctl stop lighttpd
sudo systemctl disable lighttpd

# Then restart memory service
sudo systemctl restart mcp-memory
```

## ✅ **Success Indicators**

When everything is working correctly, you should see:

1. **Service Status**: `Active: active (running)`
2. **API Response**: `{"status": "healthy"}` 
3. **mDNS Discovery**: Service visible on multiple interfaces
4. **HTTPS Access**: Dashboard accessible at https://localhost:8000
5. **Auto-Startup**: Service starts automatically on boot
6. **Consolidation**: Logs show consolidation system enabled
7. **Client Connections**: Multiple clients can connect simultaneously

---

**🎉 Your MCP Memory Service is now fully operational with consolidation, mDNS auto-discovery, HTTPS, and automatic startup!**
```

--------------------------------------------------------------------------------
/scripts/pr/auto_review.sh:
--------------------------------------------------------------------------------

```bash
#!/bin/bash
# scripts/pr/auto_review.sh - Automated PR review loop using Gemini CLI
#
# Usage: bash scripts/pr/auto_review.sh <PR_NUMBER> [MAX_ITERATIONS] [SAFE_FIX_MODE]
# Example: bash scripts/pr/auto_review.sh 123 5 true

set -e

# Get script directory for sourcing helpers
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"

# Source GraphQL helpers for thread resolution
if [ -f "$SCRIPT_DIR/lib/graphql_helpers.sh" ]; then
    source "$SCRIPT_DIR/lib/graphql_helpers.sh"
    GRAPHQL_AVAILABLE=true
else
    echo "Warning: GraphQL helpers not available, thread auto-resolution disabled"
    GRAPHQL_AVAILABLE=false
fi

PR_NUMBER=$1
MAX_ITERATIONS=${2:-5}
SAFE_FIX_MODE=${3:-true}

if [ -z "$PR_NUMBER" ]; then
    echo "Usage: $0 <PR_NUMBER> [MAX_ITERATIONS] [SAFE_FIX_MODE]"
    echo "Example: $0 123 5 true"
    exit 1
fi

# Check dependencies
if ! command -v gh &> /dev/null; then
    echo "Error: GitHub CLI (gh) is not installed"
    echo "Install: https://cli.github.com/"
    exit 1
fi

if ! command -v gemini &> /dev/null; then
    echo "Error: Gemini CLI is not installed"
    exit 1
fi

echo "=== Automated PR Review Loop ==="
echo "PR Number: #$PR_NUMBER"
echo "Max Iterations: $MAX_ITERATIONS"
echo "Safe Fix Mode: $SAFE_FIX_MODE"
echo "GraphQL Thread Resolution: $([ "$GRAPHQL_AVAILABLE" = true ] && echo "Enabled" || echo "Disabled")"
echo ""

# Get repository from git remote (portable across forks)
REPO=$(gh repo view --json nameWithOwner -q .nameWithOwner 2>/dev/null || echo "doobidoo/mcp-memory-service")

iteration=1
approved=false

while [ $iteration -le $MAX_ITERATIONS ] && [ "$approved" = false ]; do
    echo "=== Iteration $iteration/$MAX_ITERATIONS ==="

    # Trigger Gemini review (use /gemini review for inline comments)
    echo "Requesting Gemini code review (inline comments)..."
    gh pr comment $PR_NUMBER --body "/gemini review"

    # Wait for Gemini to process
    echo "Waiting for Gemini review (90 seconds)..."
    sleep 90

    # Fetch latest review status and comments
    echo "Fetching review feedback..."

    # Get review state (APPROVED, CHANGES_REQUESTED, COMMENTED)
    review_state=$(gh pr view $PR_NUMBER --json reviews --jq '[.reviews[] | select(.author.login == "gemini-code-assist[bot]")] | last | .state')

    # Fetch actual comment bodies for categorization first
    review_comments=$(gh api "repos/$REPO/pulls/$PR_NUMBER/comments" | \
        jq -r '[.[] | select(.user.login == "gemini-code-assist[bot]")] | .[] | "- \(.path):\(.line) - \(.body[0:200])"' | \
        head -50)

    # Get inline review comments count
    review_comments_count=$(gh api "repos/$REPO/pulls/$PR_NUMBER/comments" | jq '[.[] | select(.user.login == "gemini-code-assist[bot]")] | length')

    echo "Review State: $review_state"
    echo "Inline Comments: $review_comments_count"

    # Display thread status if GraphQL available
    if [ "$GRAPHQL_AVAILABLE" = true ]; then
        thread_stats=$(get_thread_stats "$PR_NUMBER" 2>/dev/null || echo '{"total":0,"resolved":0,"unresolved":0}')
        total_threads=$(echo "$thread_stats" | jq -r '.total // 0')
        resolved_threads=$(echo "$thread_stats" | jq -r '.resolved // 0')
        unresolved_threads=$(echo "$thread_stats" | jq -r '.unresolved // 0')
        echo "Review Threads: $total_threads total, $resolved_threads resolved, $unresolved_threads unresolved"
    fi

    echo ""

    # Check if approved
    if [ "$review_state" = "APPROVED" ]; then
        echo "✅ PR approved by Gemini!"
        approved=true
        break
    fi

    # If no inline comments, we're done
    if [ "$review_comments_count" -eq 0 ] && [ "$review_state" != "CHANGES_REQUESTED" ]; then
        echo "✅ No issues found in review"
        approved=true
        break
    fi

    # Extract actionable issues
    if [ "$SAFE_FIX_MODE" = true ]; then
        echo "Analyzing feedback for safe auto-fixes..."

        # Get PR diff
        pr_diff=$(gh pr diff $PR_NUMBER)

        # Use Gemini to categorize issues (request JSON format)
        categorization=$(gemini "Categorize these code review comments into a JSON object.

Review feedback:
$review_comments

Categories:
- safe: Simple fixes (formatting, imports, type hints, docstrings, variable renaming)
- unsafe: Logic changes, API modifications, security-critical code
- non_code: Documentation, discussion, questions

IMPORTANT: Output ONLY valid JSON in this exact format:
{
  \"safe\": [\"issue 1\", \"issue 2\"],
  \"unsafe\": [\"issue 1\"],
  \"non_code\": [\"comment 1\"]
}")

        echo "$categorization"

        # Extract safe issues using jq
        safe_issues=$(echo "$categorization" | jq -r '.safe[]' 2>/dev/null || echo "")

        if [ -z "$safe_issues" ]; then
            echo "No safe auto-fixable issues found. Manual intervention required."
            break
        fi

        echo ""
        echo "Safe issues to auto-fix:"
        echo "$safe_issues"
        echo ""

        # Generate fixes for safe issues
        echo "Generating code fixes..."
        fixes=$(gemini "Generate git diff patches for these safe fixes:

Issues to fix:
$safe_issues

Current code (PR diff):
$pr_diff

Output only the git diff patch that can be applied with 'git apply'. Include file paths and line numbers.")

        # Use mktemp for patch file
        patch_file=$(mktemp -t pr_fixes_${PR_NUMBER}_${iteration}.XXXXXX)
        echo "$fixes" > "$patch_file"

        # Attempt to apply fixes
        echo "Attempting to apply fixes..."
        if git apply --check "$patch_file" 2>/dev/null; then
            git apply "$patch_file"
            git add -A

            # Create commit message
            commit_msg="fix: apply Gemini review feedback (iteration $iteration)

Addressed:
$safe_issues

Co-Authored-By: Gemini Code Assist <[email protected]>"

            git commit -m "$commit_msg"
            git push

            echo "✅ Fixes applied and pushed"

            # Auto-resolve review threads for files we just fixed
            if [ "$GRAPHQL_AVAILABLE" = true ]; then
                echo ""
                echo "Resolving review threads for fixed code..."

                # Get the commit SHA we just created
                latest_commit=$(git rev-parse HEAD)

                # Run thread resolution in auto mode
                if bash "$SCRIPT_DIR/resolve_threads.sh" "$PR_NUMBER" "$latest_commit" --auto 2>&1 | grep -q "Resolved:"; then
                    echo "✅ Review threads auto-resolved"
                else
                    echo "ℹ️  No threads needed resolution"
                fi
            fi

            # Clean up temp file
            rm -f "$patch_file"
        else
            echo "⚠️  Could not auto-apply fixes. Patch saved to $patch_file"
            echo "Manual application required."
            break
        fi
    else
        echo "Manual fix mode enabled. Review feedback above and apply manually."
        break
    fi

    iteration=$((iteration + 1))
    echo ""
    echo "Waiting 10 seconds before next iteration..."
    sleep 10
done

echo ""
echo "=== Review Loop Complete ==="

if [ "$approved" = true ]; then
    echo "🎉 PR #$PR_NUMBER is approved and ready to merge!"
    gh pr comment $PR_NUMBER --body "✅ **Automated Review Complete**

All review iterations completed successfully. PR is approved and ready for merge.

Iterations: $((iteration - 1))/$MAX_ITERATIONS"
    exit 0
else
    echo "⚠️  Max iterations reached or manual intervention needed"
    gh pr comment $PR_NUMBER --body "⚠️ **Automated Review Incomplete**

Review loop completed $((iteration - 1)) iterations but approval not received.
Manual review and intervention may be required.

Please review the latest feedback and apply necessary changes."
    exit 1
fi

```

--------------------------------------------------------------------------------
/scripts/service/service_utils.py:
--------------------------------------------------------------------------------

```python
#!/usr/bin/env python3
"""
Shared utilities for cross-platform service installation.
Provides common functionality for all platform-specific service installers.
"""
import os
import sys
import json
import secrets
import platform
import subprocess
from pathlib import Path
from typing import Dict, Optional, Tuple


def get_project_root() -> Path:
    """Get the project root directory."""
    current_file = Path(__file__).resolve()
    return current_file.parent.parent


def get_python_executable() -> str:
    """Get the current Python executable path."""
    return sys.executable


def get_venv_path() -> Optional[Path]:
    """Get the virtual environment path if in a venv."""
    if hasattr(sys, 'real_prefix') or (hasattr(sys, 'base_prefix') and sys.base_prefix != sys.prefix):
        return Path(sys.prefix)
    return None


def generate_api_key() -> str:
    """Generate a secure API key for the service."""
    return f"mcp-{secrets.token_hex(16)}"


def get_service_paths() -> Dict[str, Path]:
    """Get common paths used by the service."""
    project_root = get_project_root()
    
    paths = {
        'project_root': project_root,
        'scripts_dir': project_root / 'scripts',
        'src_dir': project_root / 'src',
        'venv_dir': get_venv_path() or project_root / 'venv',
        'config_dir': Path.home() / '.mcp_memory_service',
        'log_dir': Path.home() / '.mcp_memory_service' / 'logs',
    }
    
    # Ensure config and log directories exist
    paths['config_dir'].mkdir(parents=True, exist_ok=True)
    paths['log_dir'].mkdir(parents=True, exist_ok=True)
    
    return paths


def get_service_environment() -> Dict[str, str]:
    """Get environment variables for the service."""
    paths = get_service_paths()
    venv_path = get_venv_path()
    
    env = {
        'PYTHONPATH': str(paths['src_dir']),
        'MCP_MEMORY_STORAGE_BACKEND': os.getenv('MCP_MEMORY_STORAGE_BACKEND', 'sqlite_vec'),
        'MCP_HTTP_ENABLED': 'true',
        'MCP_HTTP_HOST': '0.0.0.0',
        'MCP_HTTP_PORT': '8000',
        'MCP_HTTPS_ENABLED': 'true',
        'MCP_MDNS_ENABLED': 'true',
        'MCP_MDNS_SERVICE_NAME': 'memory',
        'MCP_CONSOLIDATION_ENABLED': 'true',
    }
    
    # Add venv to PATH if available
    if venv_path:
        bin_dir = venv_path / ('Scripts' if platform.system() == 'Windows' else 'bin')
        current_path = os.environ.get('PATH', '')
        env['PATH'] = f"{bin_dir}{os.pathsep}{current_path}"
    
    return env


def save_service_config(config: Dict[str, any]) -> Path:
    """Save service configuration to file."""
    paths = get_service_paths()
    config_file = paths['config_dir'] / 'service_config.json'
    
    with open(config_file, 'w') as f:
        json.dump(config, f, indent=2)
    
    return config_file


def load_service_config() -> Optional[Dict[str, any]]:
    """Load service configuration from file."""
    paths = get_service_paths()
    config_file = paths['config_dir'] / 'service_config.json'
    
    if config_file.exists():
        with open(config_file, 'r') as f:
            return json.load(f)
    return None


def check_dependencies() -> Tuple[bool, str]:
    """Check if all required dependencies are installed."""
    try:
        # Check Python version
        if sys.version_info < (3, 10):
            return False, f"Python 3.10+ required, found {sys.version}"
        
        # Check if in virtual environment (recommended)
        if not get_venv_path():
            print("WARNING: Not running in a virtual environment")
        
        # Check core dependencies
        required_modules = [
            'mcp',
            'chromadb',
            'sentence_transformers',
        ]
        
        missing = []
        for module in required_modules:
            try:
                __import__(module)
            except ImportError:
                missing.append(module)
        
        if missing:
            return False, f"Missing dependencies: {', '.join(missing)}"
        
        return True, "All dependencies satisfied"
        
    except Exception as e:
        return False, f"Error checking dependencies: {str(e)}"


def get_service_command() -> list:
    """Get the command to run the service."""
    paths = get_service_paths()
    python_exe = get_python_executable()
    
    # Use HTTP server script if available, otherwise fall back to main server
    http_server = paths['scripts_dir'] / 'run_http_server.py'
    main_server = paths['scripts_dir'] / 'run_memory_server.py'
    
    if http_server.exists():
        return [python_exe, str(http_server)]
    elif main_server.exists():
        return [python_exe, str(main_server)]
    else:
        # Fall back to module execution
        return [python_exe, '-m', 'mcp_memory_service.server']


def test_service_startup() -> Tuple[bool, str]:
    """Test if the service can start successfully."""
    try:
        cmd = get_service_command()
        env = os.environ.copy()
        env.update(get_service_environment())
        
        # Try to start the service briefly
        proc = subprocess.Popen(
            cmd,
            env=env,
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
            text=True
        )
        
        # Give it a moment to start
        import time
        time.sleep(2)
        
        # Check if process is still running
        if proc.poll() is None:
            # Service started successfully, terminate it
            proc.terminate()
            proc.wait(timeout=5)
            return True, "Service starts successfully"
        else:
            # Process exited, get error
            stdout, stderr = proc.communicate()
            error_msg = stderr or stdout or "Unknown error"
            return False, f"Service failed to start: {error_msg}"
            
    except Exception as e:
        return False, f"Error testing service: {str(e)}"


def print_service_info(api_key: str, platform_specific_info: Dict[str, str] = None):
    """Print service installation information."""
    print("\n" + "=" * 60)
    print("✅ MCP Memory Service Installed Successfully!")
    print("=" * 60)
    
    print("\n📌 Service Information:")
    print(f"  API Key: {api_key}")
    print(f"  Dashboard: https://localhost:8000")
    print(f"  API Docs: https://localhost:8000/api/docs")
    print(f"  Health Check: https://localhost:8000/api/health")
    
    if platform_specific_info:
        print("\n🖥️  Platform-Specific Commands:")
        for key, value in platform_specific_info.items():
            print(f"  {key}: {value}")
    
    print("\n📝 Configuration:")
    config = load_service_config()
    if config:
        print(f"  Config File: {get_service_paths()['config_dir'] / 'service_config.json'}")
        print(f"  Log Directory: {get_service_paths()['log_dir']}")
    
    print("\n" + "=" * 60)


def is_admin() -> bool:
    """Check if running with administrative privileges."""
    system = platform.system()
    
    if system == "Windows":
        try:
            import ctypes
            return ctypes.windll.shell32.IsUserAnAdmin() != 0
        except:
            return False
    else:  # Unix-like systems
        return os.geteuid() == 0


def require_admin(message: str = None):
    """Ensure the script is running with admin privileges."""
    if not is_admin():
        system = platform.system()
        if message:
            print(f"\n❌ {message}")
        
        if system == "Windows":
            print("\nPlease run this script as Administrator:")
            print("  Right-click on your terminal and select 'Run as Administrator'")
        else:
            print("\nPlease run this script with sudo:")
            script_name = sys.argv[0]
            print(f"  sudo {' '.join(sys.argv)}")
        
        sys.exit(1)
```
Page 8/35FirstPrevNextLast