🇬🇧 English • 🇷🇺 Русский • 🇨🇳 中文
A document for developers joining the project. Describes key architectural decisions, Windows pitfalls, and investigation results, so you don't step on the same rake.
MSCodeBase Intelligence — an MCP server for semantic code search in Zed IDE. Runs fully locally: LanceDB (vector index) + ONNX E5-base INT8 (in-process embeddings) + llama.cpp GGUF (reranker only) + OpenVINO INT8 (optional).
Key numbers:
- 37 MCP tools (42 core + 12 intel + 3 diagnostic) — including
query_graph(Cypher engine) - 11 tool files, 16 services in the DI container
- Index: ~3000 chunks, ~170 files, ~1550 symbols
- PropertyGraph: SQLite graph (15 node types, 27 edge types) in
.codebase/graph.db
Problem: The MCP server needs to know which project is open in the Zed window.
ZED_WORKTREE_ROOT and current_dir don't work on Windows (Zed bug).
Each window starts its own MCP process, but environment variables aren't passed.
Solution: read Zed's SQLite database directly:
# 1. Get active_workspace_id from scoped_kv_store
conn.execute("""
SELECT value FROM scoped_kv_store
WHERE namespace = 'multi_workspace_state'
""")
# → {"active_workspace_id": 2, ...}
# 2. Get the path by ID
conn.execute("""
SELECT paths FROM workspaces WHERE workspace_id = ?
""", (active_id,))
# → "D:\path\to\project"Where: src/mcp/server.py, function resolve_project_root(), priority 0.
Limitation: if a project has multiple windows — MCP doesn't know which one is active.
→ Full investigation: ACTIVE_WORKSPACE_RESOLUTION.md
Covers: 6 tested Zed mechanisms, internal Rust APIs, SQLite schemas, 4 failed approaches.
| Decision | Motivation |
|---|---|
| DI container (ServiceCollection) | 16 services, lazy resolution, per-project registry + PropertyGraph |
| late-resolve active indexer | If LSP hasn't written the bridge file yet — pick up the first live workspace |
| Two-phase reindex | intel_trigger_reindex → job_id → intel_get_job_status (anti-spam) |
| asyncio.Lock for File IO | Race protection for concurrent writes to memory JSON files |
| ui_formatter | Unified Markdown style for all 37 tools (no raw JSON) |
| Component | Reason | Status |
|---|---|---|
LSP server (lsp_main.py) |
Standalone LSP — Zed doesn't register custom LSP names. LSP client for rename (lsp_client.py) works fine |
WONTFIX (standalone only) |
| auto-restart MCP | No hook in Zed to restart a crashed context_server | WONTFIX |
ZED_WORKTREE_ROOT |
Not set on Windows (Zed bug #36019) | Workaround via SQLite |
→ Full LSP investigation: LSP_WONTFIX.md
Summary: Zed requires a Rust/WASM adapter for a custom LSP. settings.json cannot
register a new language — only override the path for an existing one.
8 approaches tested, all failed.
File: src/core/rate_limiter.py
Symptom: MCP hangs 5 seconds after a batch of notify_change.
Cause: await inside threading.Lock (not reentrant) — 100% deadlock.
Fix: separation: should_flush decision under lock, the await itself — after releasing the lock.
MCP server sometimes indexed itself (extension sources, ~500MB).
Fix: _is_self_index_path() check in base.py — blocks ext_root
and the Zed installation directory, throws ToolError.
Concurrent calls to intel_log_incident + intel_add_memory_node overwrote
JSON files. Fix: asyncio.Lock in IntelligenceStore.
| Data | Path |
|---|---|
| Vector index | <project>/.codebase_indices/lancedb_v2/ |
| Project memory (ADR, issues) | <project>/.codebase_indices/intelligence/ |
| Logs | %LOCALAPPDATA%\Zed\extensions\mscodebase-intelligence\.codebase_indices\logs\ |
| Zed's database | %LOCALAPPDATA%\Zed\db\0-stable\db.sqlite |
| File | What it does |
|---|---|
src/mcp/server.py |
resolve_project_root(), registration of all 37 tools |
src/mcp/tools/base.py |
MCPTool (base class), resolve_indexer_for_request() |
src/core/di_container.py |
15 services, ProjectIndexerRegistry |
src/core/intelligence_layer.py |
12 intel tools, ProjectIntelligenceLayer |
src/core/indexer.py |
LanceDB, vectorization, indexing |
src/core/searcher.py |
BM25 + Dense + RRF hybrid search |
src/utils/ui_formatter.py |
Unified Markdown format for all tools |
src/core/error_handler.py |
_format_success_response, error_boundary |
src/core/rate_limiter.py |
DebounceBatch, SlidingWindowRateLimiter |
- Restricted Mode — press "Trust and Continue" when opening a project for the first time
- MCP restart — only File → Quit (not
window: reload, not kill) - Git subprocess —
GIT_ASKPASS=echo,CREATE_NO_WINDOW, timeouts - LanceDB on Windows — mmap files aren't released until
_safe_close()+gc.collect() - Paths — MCP:
src\core\file_guard.py, terminal:src/core/file_guard.py
| Document | About |
|---|---|
INSTALL.md |
Installation for users |
ARCHITECTURE.md |
Full architecture (10 layers) |
ZED_WINDOWS_QUIRKS.md |
Windows specifics |
investigations/LSP_WONTFIX.md |
Why LSP doesn't work |
investigations/ACTIVE_WORKSPACE_RESOLUTION.md |
SQLite active_workspace |
../../AGENTS.md |
Rules for AI agent in Zed |