文档搜索服务器

Sextant是一个基于MCP协议的本地混合语义和关键词文档搜索服务器,支持对Markdown文件进行索引和检索。

  • by Tideshift-Labs
  • TypeScript
  • 本地部署
  • 2 星标
  • 更新于
在 GitHub 查看 Tideshift-Labs/sextant

使用说明

Sextant

Sextant is an MCP server that provides hybrid semantic and keyword search over a local folder of markdown files. It indexes your docs, chunks them by heading, embeds them through a local Ollama model, and exposes search and retrieval tools over the Model Context Protocol (MCP).

Claude Code (or any MCP client) can then search your documentation using natural language queries, exact keyword lookups, or a combination of both.

How it works

  1. Sextant scans a folder of markdown files and splits them into chunks at each heading boundary.
  2. Each chunk is embedded locally using Ollama (nomic-embed-text).
  3. Chunks and their embeddings are stored in Orama, which handles full-text, vector, and hybrid search in a single library.
  4. File metadata is tracked in SQLite (via bun:sqlite) so unchanged files are skipped on restart.
  5. Each search request checks for stale files and triggers a background reindex if needed.
  6. The MCP server exposes five tools over stdio: search_docs, list_docs, get_doc, reindex_docs, and sextant_status.

The entire stack runs locally with no external services. There are no native modules; everything is pure JavaScript/TypeScript.

Shared daemon

The process an MCP client spawns is a thin stdio shim, not the full server. The shim attaches to a shared per-project daemon (starting one automatically if none is running) and proxies requests to it over localhost HTTP. This means any number of concurrent sessions on the same project share a single in-memory index instead of each holding their own copy.

Lifecycle is automatic in both directions: the first session starts the daemon, and shortly after the last session ends the daemon flushes its index to disk and exits. An idle timeout also stops the daemon after a period with no requests; it restarts transparently on the next search. The daemon binds to 127.0.0.1 only, rejects requests from browsers, and requires a per-run token that shims read from DATA_PATH/daemon.lock. Its log is written to DATA_PATH/daemon.log.

Two escape hatches exist: sextant serve runs the daemon in the foreground explicitly, and sextant standalone runs the old single-process stdio server with no daemon involved.

Index freshness

Sextant keeps its index up to date automatically:

  • On startup, Sextant compares every file's modification time against what was previously indexed. New and changed files are re-indexed; deleted files are removed from the index. This covers cases where docs were updated while the server was not running (for example, after a git pull).
  • On each search, a freshness check detects new, modified, or deleted files and triggers a background reindex without blocking the query. If files have changed, the response includes a note and results update on the next search.
  • If another Sextant process has persisted a newer index to disk, it is picked up automatically before searching.

Prerequisites

Bun

Sextant runs on Bun, which is used as the runtime, package manager, and bundler.

Windows (PowerShell):

powershell -c "irm bun.sh/install.ps1 | iex"

macOS / Linux:

curl -fsSL https://bun.sh/install | bash

Verify the installation with bun --version.

Ollama

Ollama must be installed and running locally. Pull the embedding model before first use:

ollama pull nomic-embed-text

Ollama runs on http://localhost:11434 by default. If Ollama is not running, keyword search will still work, but semantic and hybrid search will be unavailable.

Usage with Claude Code

Add the following to your Claude Code MCP configuration (.claude/mcp.json in your project):

{
  "mcpServers": {
    "sextant": {
      "type": "stdio",
      "command": "bunx",
      "args": ["@tideshift/sextant"],
      "env": {
        "DOCS_PATH": "/absolute/path/to/your/docs"
      }
    }
  }
}

Set DOCS_PATH to the absolute path of the markdown folder you want to index.

Once configured, Claude Code will have access to the following tools:

  • search_docs - Search documentation using hybrid semantic + keyword search. Supports three modes: hybrid (default, combines both), semantic (vector similarity only), and keyword (exact text matching only). Accepts an optional category filter.
  • list_docs - List all indexed documents with their categories, titles, and chunk counts.
  • get_doc - Retrieve the full content of a specific document by file path.
  • reindex_docs - Force a full re-index of all documents.
  • sextant_status - Check server health, indexing progress, Ollama connectivity, and index statistics.

Configuration

All settings can be configured through environment variables or a .env file:

Variable Default Description
DOCS_PATH ./docs Path to the markdown folder to index
IGNORE_GLOBS **/node_modules/** Comma-separated glob patterns (relative to DOCS_PATH, posix separators) to skip. Empty value indexes everything
OLLAMA_URL http://localhost:11434 Ollama API endpoint
EMBEDDING_MODEL nomic-embed-text Ollama embedding model name
EMBEDDING_DIMS 768 Embedding vector dimensions (must match model)
DATA_PATH .sextant Where to store the index and metadata
MAX_CHUNK_TOKENS 512 Maximum chunk size (estimated as chars / 4)
DEFAULT_TOP_K 10 Default number of search results
HYBRID_WEIGHT_TEXT 0.5 Weight for keyword matching in hybrid mode
HYBRID_WEIGHT_VECTOR 0.5 Weight for semantic matching in hybrid mode
SEXTANT_PORT 0 Daemon port (0 = OS-assigned; recorded in DATA_PATH/daemon.lock)
SEXTANT_GRACE_MS 60000 How long the daemon waits after the last client disconnects before exiting
SEXTANT_IDLE_TIMEOUT_MS 600000 Daemon exits after this long with no requests (restarts on next use)
SEXTANT_LOG_FILE DATA_PATH/daemon.log Daemon log file
SEXTANT_SPAWN_TIMEOUT_MS 30000 How long the shim waits for a spawned daemon to become healthy
SEXTANT_FRESHNESS_TTL_MS 5000 Minimum interval between per-search freshness scans
SEXTANT_OLLAMA_HEALTH_TTL_MS 5000 Cache duration for Ollama health checks

Contributing

See docs/contributing.md for local development setup, building, and diagnostics.

Technical details

See docs/technical_details.md for architecture, project structure, chunking strategy, persistence model, index freshness logic, and edge cases.

License

Made with ❤️ in Vancouver, BC by Tideshift Labs, developed using Claude Code.

MIT