diff --git a/README.md b/README.md
deleted file mode 100644
index a189b19..0000000
--- a/README.md
+++ /dev/null
@@ -1,29 +0,0 @@
-# metal-kompanion-mcp
-
-MCP backend and memory provider for Kompanion. Uses `qtmcp` (Qt-based MCP) to expose tools under namespace `kom.memory.v1`.
-
-## Build
-```bash
-cmake -S . -B build
-cmake --build build -j
-```
-
-## Layout
-- `src/main.cpp` – QtMcp-backed entry point (stdio/SSE backends)
-- `src/mcp/ToolSchemas.json` – JSON Schemas for MCP tools
-- `src/memory/` – interfaces for embedder and vector store
-- `docs/` – design notes
-
-## Next
-- Add richer tool metadata + prompt support on top of the qtmcp server.
-- Implement adapters: embedder(s) + vector store(s).
-- Flesh out Postgres DAL paths (prepared statements + pgvector wiring).
-
-## Memory Tools
-- `kom.memory.v1.save_context` persists conversational or workspace state in a namespace.
-- `kom.memory.v1.recall_context` retrieves stored context by key, tags, or time window.
-- See `docs/using-memory-tools.md` for integration notes (Codey, Claude Code) and request samples.
-
-## Integrations
-- **Kompanion-Konsole** — demo plugin for KDE Konsole that lets agents hand terminals over to the Kompanion runtime. See `integrations/konsole/README.md`.
-- **JavaScript helpers** — Node.js utilities that call the MCP memory tools from scripts or web extensions. See `integrations/js/`.
diff --git a/build.log b/build.log
deleted file mode 100644
index dca2832..0000000
--- a/build.log
+++ /dev/null
@@ -1,18 +0,0 @@
-[  0%] Built target kom_dal_autogen_timestamp_deps
-[  4%] Built target kom_dal_autogen
-[ 16%] Built target kom_dal
-[ 16%] Built target kom_mcp_autogen_timestamp_deps
-[ 20%] Built target kom_mcp_autogen
-[ 33%] Built target kom_mcp
-[ 33%] Built target kompanion_autogen_timestamp_deps
-[ 37%] Built target kompanion_autogen
-[ 50%] Built target kompanion
-[ 50%] Built target test_mcp_tools_autogen_timestamp_deps
-[ 54%] Built target test_mcp_tools_autogen
-[ 66%] Built target test_mcp_tools
-[ 66%] Built target contract_memory_autogen_timestamp_deps
-[ 70%] Built target contract_memory_autogen
-[ 83%] Built target contract_memory
-[ 83%] Built target test_memory_exchange_autogen_timestamp_deps
-[ 87%] Built target test_memory_exchange_autogen
-[100%] Built target test_memory_exchange
diff --git a/db/init/012_test_user.sql b/db/init/012_test_user.sql
new file mode 100644
index 0000000..0364fde
--- /dev/null
+++ b/db/init/012_test_user.sql
@@ -0,0 +1,11 @@
+-- Create the dev_knowledge namespace if it doesn't exist
+INSERT INTO namespaces (name) VALUES ('dev_knowledge') ON CONFLICT (name) DO NOTHING;
+
+-- Create a secret for the dev_knowledge namespace for testing
+DO $$
+DECLARE
+    ns_id UUID;
+BEGIN
+    SELECT id INTO ns_id FROM namespaces WHERE name = 'dev_knowledge';
+    INSERT INTO auth_secrets (namespace_id, secret_hash) VALUES (ns_id, '8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918'); -- 'test-secret'
+END $$;
diff --git a/db/scripts/create-test-db.sh b/db/scripts/create-test-db.sh
index b1ac32d..15493da 100755
--- a/db/scripts/create-test-db.sh
+++ b/db/scripts/create-test-db.sh
@@ -9,7 +9,7 @@ DROP DATABASE IF EXISTS "$DB_NAME";
 CREATE DATABASE "$DB_NAME" OWNER "$ROLE";
 SQL
 
-for f in `dirname($0)`/*.sql; do
+for f in "$(dirname "$0")"/../init/*.sql; do
   if [[ "$f" == *"001_roles.sql"* ]]; then
     continue
   fi
diff --git a/doc/anything-llm-eval.md b/docs/anything-llm-eval.md
similarity index 100%
rename from doc/anything-llm-eval.md
rename to docs/anything-llm-eval.md
diff --git a/doc/client-memory.md b/docs/client-memory.md
similarity index 100%
rename from doc/client-memory.md
rename to docs/client-memory.md
diff --git a/doc/ideas.txt b/docs/ideas.txt
similarity index 100%
rename from doc/ideas.txt
rename to docs/ideas.txt
diff --git a/doc/plugin-architecture.md b/docs/plugin-architecture.md
similarity index 100%
rename from doc/plugin-architecture.md
rename to docs/plugin-architecture.md
diff --git a/ledger.md b/ledger.md
deleted file mode 100644
index 912cf0a..0000000
--- a/ledger.md
+++ /dev/null
@@ -1,5 +0,0 @@
-# Ledger
-
-- 2025-10-13: Initialized project `metal-kompanion-mcp`; created docs and interfaces; scaffolded CMake and main stub.
-- 2025-10-13: Added MCP tool schemas for `kom.memory.v1`.
-- 2025-10-13: Built MCP skeleton with `ping` and `embed_text` stub; added local-first architecture docs; added backup/sync draft specs; created tasks for privacy hardening and cloud adapters.
diff --git a/tests/e2e_mcp_test.sh b/tests/e2e_mcp_test.sh
new file mode 100755
index 0000000..3f83e40
--- /dev/null
+++ b/tests/e2e_mcp_test.sh
@@ -0,0 +1,147 @@
+#!/usr/bin/env bash
+set -euo pipefail
+set -x
+
+# --- Test Configuration ---
+TEST_DB_NAME="kompanion_autotest"
+MCP_SERVER_EXECUTABLE="./bin/kom_mcp"
+PROJECT_ROOT_DIR=$(git rev-parse --show-toplevel)
+MCP_SERVER_HOST="127.0.0.1"
+MCP_SERVER_PORT="8081"
+MCP_SERVER_URL="http://${MCP_SERVER_HOST}:${MCP_SERVER_PORT}"
+
+# --- Cleanup Function ---
+cleanup() {
+    echo "--- Cleaning up ---"
+    pkill -f kom_mcp || true
+    sleep 1 # Give the OS time to release the port
+    netstat -tuln | grep ":${MCP_SERVER_PORT}" || true # Check if port is still in use
+    psql -v ON_ERROR_STOP=1 -c "DROP DATABASE IF EXISTS \"$TEST_DB_NAME\";" >/dev/null 2>&1
+}
+
+trap cleanup EXIT
+
+echo "--- Setting up test environment ---"
+
+echo ">> Initializing test database..."
+"${PROJECT_ROOT_DIR}/db/scripts/create-test-db.sh" "$TEST_DB_NAME"
+
+echo ">> Harvesting embeddings..."
+export DB_URL="dbname=${TEST_DB_NAME} user=kompanion host=/var/run/postgresql" EMBED_NAMESPACE="dev_knowledge"
+python3 "${PROJECT_ROOT_DIR}/tools/ingest_dir.py" "${PROJECT_ROOT_DIR}/tests/test_data" "dev_knowledge"
+
+echo ">> Starting MCP server..."
+$MCP_SERVER_EXECUTABLE --backend sse --address "${MCP_SERVER_HOST}:${MCP_SERVER_PORT}" &
+mcp_server_pid=$!
+
+sleep 3
+
+# --- API Test Functions ---
+
+send_request() {
+    local session_id=$1
+    local payload=$2
+    curl -s -X POST -H "Content-Type: application/json" -d "$payload" "${MCP_SERVER_URL}/messages?session_id=${session_id}"
+}
+
+# --- Running API tests ---
+
+echo "--> Establishing SSE connection..."
+SSE_RESPONSE=$(curl -s -N -H "Accept:text/event-stream" "${MCP_SERVER_URL}/")
+sleep 1 # Give the server time to send the response
+SESSION_ID=$(echo "$SSE_RESPONSE" | grep -oE 'data: /messages/\?session_id=([a-f0-9-]+)' | cut -d '=' -f 2)
+
+if [ -z "$SESSION_ID" ]; then
+    echo "Failed to get session ID"
+    exit 1
+fi
+
+echo "Session ID: $SESSION_ID"
+
+# Test upsert_memory
+echo "--> Testing upsert_memory..."
+UPSERT_PAYLOAD='{
+  "jsonrpc": "2.0",
+  "method": "tool",
+  "params": {
+    "name": "kom.memory.v1.upsert_memory",
+    "arguments": {
+      "auth_token": "dev_knowledge:test-secret",
+      "namespace": "dev_knowledge",
+      "items": [
+        {
+          "id": "test-item-1",
+          "text": "This is a test item for upsert_memory.",
+          "tags": ["test", "upsert"]
+        }
+      ]
+    }
+  }
+}'
+
+response=$(send_request "$SESSION_ID" "$UPSERT_PAYLOAD")
+echo "$response" | grep '"status":"ok"' > /dev/null || (echo "upsert_memory test failed" && exit 1)
+echo "upsert_memory test passed."
+
+# Test search_memory
+echo "--> Testing search_memory..."
+SEARCH_PAYLOAD='{
+  "jsonrpc": "2.0",
+  "method": "tool",
+  "params": {
+    "name": "kom.memory.v1.search_memory",
+    "arguments": {
+      "auth_token": "dev_knowledge:test-secret",
+      "namespace": "dev_knowledge",
+      "query": {
+        "text": "upsert"
+      }
+    }
+  }
+}'
+
+response=$(send_request "$SESSION_ID" "$SEARCH_PAYLOAD")
+echo "$response" | grep '"id":"test-item-1"' > /dev/null || (echo "search_memory test failed" && exit 1)
+echo "search_memory test passed."
+
+# Test save_context
+echo "--> Testing save_context..."
+SAVE_CONTEXT_PAYLOAD='{
+  "jsonrpc": "2.0",
+  "method": "tool",
+  "params": {
+    "name": "kom.memory.v1.save_context",
+    "arguments": {
+      "auth_token": "dev_knowledge:test-secret",
+      "namespace": "dev_knowledge",
+      "key": "test-context-1",
+      "content": {
+        "message": "This is a test context."
+      },
+      "tags": ["test", "context"]
+    }
+  }
+}'
+
+response=$(send_request "$SESSION_ID" "$SAVE_CONTEXT_PAYLOAD")
+echo "$response" | grep '"id":' > /dev/null || (echo "save_context test failed" && exit 1)
+echo "save_context test passed."
+
+# Test recall_context
+echo "--> Testing recall_context..."
+RECALL_CONTEXT_PAYLOAD='{
+  "jsonrpc": "2.0",
+  "method": "tool",
+  "params": {
+    "name": "kom.memory.v1.recall_context",
+    "arguments": {
+      "auth_token": "dev_knowledge:test-secret",
+      "namespace": "dev_knowledge",
+      "key": "test-context-1"
+    }
+  }
+}'
+
+response=$(send_request "$SESSION_ID" "$RECALL_CONTEXT_PAYLOAD")
+echo "$response" | grep '"key":"test-context-1"' > /dev/null || (echo "recall_context test failed" && exit 1)
+echo "recall_context test passed."
