Minimal MCP server for searchable Markdown knowledge bases (SQLite FTS5)
Project description
Talk to your docs
kenso turns a folder of Markdown docs into a searchable knowledge base for people and AI agents. Answers from your own docs. Zero config. No infrastructure. Always deterministic.
Docs · Getting Started · Editor Setup
Why kenso
Your documentation already has the answers. But finding them means remembering which file, scanning entire documents, or piecing together information scattered across multiple places. kenso does it with one question.
- Direct answers — get the right paragraph without reading the whole doc.
- Cross-document reasoning — one question, ten docs, one synthesized answer.
- Natural queries — search how you think, not how the author wrote.
- Brainstorm, audit, plan — think with your docs, not from guesses.
- Cross-domain — bridge code and business rules in one question.
Quick Start
Try without installing (requires uv):
uvx kenso ingest ./docs/ # index your markdown files
# optional — verify the index before connecting an editor
uvx kenso search "deployment pipeline"
uvx kenso stats
Or install:
pip install kenso[yaml] # install with YAML frontmatter support
kenso ingest ./docs/ # index your markdown files
# optional — verify the index before connecting an editor
kenso search "deployment pipeline"
kenso stats
That's it. Now connect your editor — the MCP client starts kenso automatically.
kenso works with any Markdown file.
To improve retrieval quality, see Writing Effective Documents.
How it compares
The LLM already understands meaning — what it lacks is the right source text. kenso finds that text with keyword search and lets the LLM reason over it.
| Embedding RAG | Wiki | kenso | |
|---|---|---|---|
| Setup | |||
| Infrastructure | Model + vector DB + pipeline | SaaS platform | — |
| Free | ✗ | ✗ | ✓ |
| Content | |||
| Visual editor | ✗ | ✓ | ✗ |
| Readable source | ✗ | ✓ | ✓ |
| Team collaboration | ✗ | ✓ | ✓ |
| Change review | ✗ | Partial | ✓ |
| Full history | ✗ | Partial | ✓ |
| CI/CD ready | ✗ | ✗ | ✓ |
| Effortless authoring | ✓ | ✓ | ✗ |
| Deterministic | ✗ | ✓ | ✓ |
| Search | |||
| Semantic search | ✓ | ✗ | ✗ |
| Keyword precision | Partial | ✗ | ✓ |
| Inspectable ranking | ✗ | ✗ | ✓ |
| Cross-doc navigation | ✗ | ✗ | ✓ |
| Vocabulary-independent | ✓ | ✗ | ✗ |
| Agent access | |||
| MCP native | ✗ | ✗ | ✓ |
| Multi-client | ✗ | ✗ | ✓ |
| Runs locally | ✗ | ✗ | ✓ |
| Non-technical access | ✗ | ✓ | ✗ |
MCP Integration
kenso is a standard MCP server. It works with any client that supports the protocol — if yours isn't listed below, set command to kenso with args ["serve"] in your client's MCP settings. If you installed in a virtualenv, use the full path to the binary as command instead — you can find it with which kenso.
For shared access across a team, kenso can also run as a remote HTTP server. See Remote Deployment.
AI Code Editors
Cursor
Create or edit .cursor/mcp.json in your project root (or ~/.cursor/mcp.json for global access):
{
"mcpServers": {
"kenso": {
"command": "kenso",
"args": ["serve"]
}
}
}
Restart Cursor after saving. The kenso tools will appear in Composer and Agent mode. See Cursor MCP docs for more info.
VS Code
Create or edit .vscode/mcp.json in your project root:
{
"servers": {
"kenso": {
"command": "kenso",
"args": ["serve"]
}
}
}
VS Code uses
"servers", not"mcpServers".
See VS Code MCP docs for more info.
Windsurf
Edit ~/.codeium/windsurf/mcp_config.json:
{
"mcpServers": {
"kenso": {
"command": "kenso",
"args": ["serve"]
}
}
}
Restart Windsurf after saving. See Windsurf MCP docs for more info.
Zed
Open your Zed settings.json (Cmd+, or Ctrl+,) and add:
{
"context_servers": {
"kenso": {
"command": {
"path": "kenso",
"args": ["serve"]
},
"settings": {}
}
}
}
See Zed Context Server docs for more info.
JetBrains
Go to Settings → Tools → AI Assistant → Model Context Protocol (MCP), click + Add, select As JSON, and paste:
{
"mcpServers": {
"kenso": {
"command": "kenso",
"args": ["serve"]
}
}
}
Click Apply to save. See JetBrains AI Assistant MCP docs for more info.
AI Assistants & CLI
Claude Code
One-liner:
claude mcp add kenso -- kenso serve
Or add to .claude/mcp.json in your project root:
{
"mcpServers": {
"kenso": {
"command": "kenso",
"args": ["serve"]
}
}
}
See Claude Code MCP docs for more info.
Claude Desktop
Open Claude Desktop settings (Settings → Developer) and edit claude_desktop_config.json:
{
"mcpServers": {
"kenso": {
"command": "kenso",
"args": ["serve"]
}
}
}
Restart Claude Desktop after saving. See Claude Desktop MCP docs for more info.
Codex CLI / Codex Desktop
Edit ~/.codex/config.toml (shared by both CLI and desktop app):
[mcp_servers.kenso]
command = "kenso"
args = ["serve"]
If you see startup timeout errors, try adding
startup_timeout_ms = 30_000.
Gemini CLI
Edit ~/.gemini/settings.json:
{
"mcpServers": {
"kenso": {
"command": "kenso",
"args": ["serve"]
}
}
}
See Gemini CLI MCP docs for more info.
Cline
Open the Cline MCP settings panel (☰ → MCP Servers), click + Add, and configure:
{
"mcpServers": {
"kenso": {
"command": "kenso",
"args": ["serve"]
}
}
}
Web interfaces
Claude and ChatGPT support connecting to remote MCP servers. This requires kenso to be deployed remotely with a public HTTPS URL.
Claude
Requires Pro, Max, Team, or Enterprise plan.
- Go to
Settings→Connectors - Click "Add custom connector"
- Paste your kenso URL (e.g.
https://kenso.your-domain.com/mcp) - Click "Add"
The kenso tools will appear in the search and tools menu of new conversations. See Claude custom connectors docs for more info.
ChatGPT
Requires Plus, Pro, Business, or Enterprise plan.
- Go to
Settings→Apps & Connectors→Advanced settings - Enable Developer Mode
- Click "Create" to add a new connector
- Paste your kenso URL (e.g.
https://kenso.your-domain.com/mcp) - Click "Create"
Enable the connector in each new conversation via the Developer Mode menu. See ChatGPT MCP docs for more info.
Multiple knowledge bases: Add one connector per kenso instance, each with its own URL and database. The LLM sees all active connectors and routes queries automatically.
Platform Notes
Windows
On Windows, wrap the command with cmd so MCP clients can locate the binary:
{
"mcpServers": {
"kenso": {
"command": "cmd",
"args": ["/c", "kenso", "serve"]
}
}
}
If kenso is installed in a virtualenv, use the full path instead:
{
"mcpServers": {
"kenso": {
"command": "C:\\Users\\you\\.venv\\Scripts\\kenso.exe",
"args": ["serve"]
}
}
}
Remote Deployment
By default, kenso runs locally over stdio. For shared access across a team, deploy it as a remote HTTP server.
KENSO_TRANSPORT=streamable-http KENSO_HOST=0.0.0.0 KENSO_PORT=8000 kenso serve
Clients connect by URL instead of command:
{
"mcpServers": {
"kenso": {
"url": "https://kenso.your-domain.com/mcp"
}
}
}
In production, place kenso behind a reverse proxy (nginx, Caddy) to add HTTPS. For local testing, use http://your-server:8000/mcp directly.
Security and platform options
Security — kenso does not include authentication. Use your reverse proxy for bearer token or basic auth, your platform's built-in auth (Cloud Run, Railway, Azure), or restrict access by network (VPN, firewall, IP allowlist).
Platform options — any platform that runs Python works: Railway, Render, Fly.io, Google Cloud Run, or a simple VPS with Docker.
Commands
kenso ingest
Scan a directory for Markdown files and load them into the database.
kenso ingest <path>
What happens under the hood
- Recursively scan for
.mdfiles, skip files under 50 characters - Hash each file (SHA-256 of the full raw text including frontmatter) — skip unchanged files
- Parse YAML frontmatter (title, category, tags, aliases, answers, relates_to)
- Split by H2 into chunks, sub-split oversized sections at H3/H4
- Capture pre-H2 content as an overview chunk ("Document Title — Overview")
- Build
searchable_contentfor each chunk = chunk text + aliases + answers + tags - Index into SQLite FTS5 with weighted columns (title 10×, section_path 8×, tags 7×, category 5×, content 1×)
- Insert
relates_toas typed bidirectional links
kenso serve
Start the MCP server.
kenso serve
kenso search
Search documents from the command line. Returns the top 5 results with score, path, title, and highlighted snippet.
kenso search <query>
What happens under the hood
- Build FTS5 cascade:
- try AND (all terms)
- then NEAR/10 (terms within 10 tokens)
- then OR (any term)
- stop at first stage with enough results
- Fetch 3× the requested limit as candidates to leave room for deduplication
- Deduplicate: keep only the highest-scoring chunk per document
- Re-rank by relation density — documents that link to other results get a score boost
- Enrich results with tags, category, and related document count
kenso lint
Analyze Markdown files for retrieval quality issues. Checks titles, tags, headings, preambles, links, and document structure against 18 rules that affect search quality.
kenso lint <path> # summary with score and prioritized fixes
kenso lint <path> --detail # per-file violations
kenso lint <path> --json # JSON output for CI integration
kenso stats
Show database statistics: document count, chunk count, storage size, links, and breakdown by category.
kenso stats
MCP Tools
| Tool | Description |
|---|---|
search_docs(query, category?, limit?) |
Keyword search with BM25 ranking, deduplication, and relation re-ranking |
search_multi(queries, category?, limit?) |
Multi-query search with Reciprocal Rank Fusion merge |
get_doc(path, max_length?) |
Retrieve full document content by path |
get_related(path, depth?, relation_type?) |
Navigate the document graph with configurable depth and relation type filter |
For detailed parameter types, defaults, and return schemas, see llms-full.txt. For how search ranking and the document graph work internally, see How kenso works.
Configuration
kenso works with zero config. All settings are optional, via environment variables.
Database
The database is created automatically on first kenso ingest. To reset, delete the file and re-ingest. Each project gets its own isolated database by default.
| Variable | Default | Description |
|---|---|---|
KENSO_DATABASE_URL |
(cascade above) | SQLite database path override |
Database location
kenso resolves the database location automatically:KENSO_DATABASE_URL— explicit override, always wins.kenso/docs.dbin the current directory — project-local (default for new projects)~/.local/share/kenso/docs.db— global fallback
Shared knowledge base across projects
```bash export KENSO_DATABASE_URL=~/.local/share/kenso/shared.db kenso ingest ./docs/ ```Important: Add
.kenso/to your.gitignore— it's a derived index, not source code.
SQLite runs in WAL mode — multiple readers can operate concurrently. Multiple
kenso serveinstances reading the same database is safe.
Remote deployment
Only needed when sharing kenso across a team. See Remote Deployment.
| Variable | Default | Description |
|---|---|---|
KENSO_TRANSPORT |
stdio |
stdio for local, streamable-http for remote |
KENSO_HOST |
127.0.0.1 |
Bind address (0.0.0.0 to expose externally) |
KENSO_PORT |
8000 |
HTTP port |
Search tuning
These affect retrieval quality. The defaults work well for most knowledge bases.
| Variable | Default | When to change |
|---|---|---|
KENSO_CHUNK_SIZE |
4000 |
Lower (2000) if your docs have many short, focused sections. Higher (6000) if sections are long and self-contained. Affects how documents are split at H2 boundaries — oversized sections get sub-split at H3/H4. |
KENSO_CHUNK_OVERLAP |
0 |
Set to 100–200 if you notice that queries miss content at section boundaries. Adds the last N characters of each chunk as prefix to the next one. |
KENSO_CONTENT_PREVIEW_CHARS |
200 |
The preview length shown to the LLM in search results. The LLM uses this to decide whether to request the full document. Increase if your lead sentences tend to be longer. |
KENSO_SEARCH_LIMIT_MAX |
20 |
Maximum results the LLM can request per search. The default of 20 is generous — most queries return useful results in the top 3–5. |
Debugging
| Variable | Default | Description |
|---|---|---|
KENSO_LOG_LEVEL |
INFO |
Set to DEBUG to see every FTS5 query, score, and chunk match |
Example
# Remote deployment with larger chunks and debug logging
KENSO_TRANSPORT=streamable-http \
KENSO_HOST=0.0.0.0 \
KENSO_CHUNK_SIZE=6000 \
KENSO_LOG_LEVEL=DEBUG \
kenso serve
Performance
Tested with a 36-query eval harness across 10 retrieval categories (exact keyword, synonym, cross-domain, vocabulary mismatch, pre-H2 content, chunk ambiguity, question-style, frontmatter enrichment, result diversity, cluster coherence):
- 100% hit rate — correct document in top 5 for every query
- 97.2% MRR — correct document at position #1 in most cases
- 5/5 feature tests for graph traversal, typed relations, and multi-query merge
- 0 regressions across 4 development sprints
Run it yourself:
python tests/eval/eval_harness.py
Benchmark against a saved snapshot:
python tests/eval/eval_harness.py --compare baseline
Writing Effective Documents
kenso works with any Markdown. But adding frontmatter significantly improves retrieval:
---
title: CI/CD Deployment Pipeline
category: infrastructure
tags: deployment, CI/CD, rollback, blue-green
aliases:
- deploy pipeline
- continuous deployment
answers:
- How is code deployed to production?
relates_to:
- path: infrastructure/monitoring.md
relation: receives_from
---
The key principles: use specific titles (indexed at 10× weight), add tags with synonyms, write a summary paragraph before the first H2, and link related documents with relates_to.
For the full guide — field reference, document structure tips, relation types, and a pre-commit checklist — see Writing Documents for kenso.
Troubleshooting
kenso search returns no results — Run kenso stats to check if docs are indexed. If zero docs, run kenso ingest <path>.
"No such table: chunks" — The database schema changed. Delete the database file (.kenso/docs.db or ~/.local/share/kenso/docs.db) and re-ingest.
MCP server not connecting — Verify the command path is correct. If installed in a venv, use the full path (e.g. /path/to/.venv/bin/kenso). Restart your editor after changing MCP config.
License
MIT
kenso — inspired by Japanese 検索 (kensaku): to search.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file kenso-1.4.0.tar.gz.
File metadata
- Download URL: kenso-1.4.0.tar.gz
- Upload date:
- Size: 221.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
842b454c5f31cce4ea21f9997346458e5c0773f070b23e5f92c3992d92be1449
|
|
| MD5 |
5719987ac6464d59f483ad1d01e700d0
|
|
| BLAKE2b-256 |
ae47b313289c440e095b093d7083753e44ff6a97a1a078ed645da89c51be9229
|
Provenance
The following attestation bundles were made for kenso-1.4.0.tar.gz:
Publisher:
ci.yml on fvena/kenso
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
kenso-1.4.0.tar.gz -
Subject digest:
842b454c5f31cce4ea21f9997346458e5c0773f070b23e5f92c3992d92be1449 - Sigstore transparency entry: 1110604370
- Sigstore integration time:
-
Permalink:
fvena/kenso@1fcf201204b517886786223573aad7a6765d2d2f -
Branch / Tag:
refs/heads/main - Owner: https://github.com/fvena
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yml@1fcf201204b517886786223573aad7a6765d2d2f -
Trigger Event:
push
-
Statement type:
File details
Details for the file kenso-1.4.0-py3-none-any.whl.
File metadata
- Download URL: kenso-1.4.0-py3-none-any.whl
- Upload date:
- Size: 41.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cef5919ff8975694ce9ab0421a8c33c13637563a05424ab5bf3f0b01a5fb8c5e
|
|
| MD5 |
5cd3112f17fb08ad09dcbd6c3aab95a5
|
|
| BLAKE2b-256 |
d5bb31077183ccbdc838b87ccbd215cf8ad167fbb4170a24d4b2fc3b4342ca2f
|
Provenance
The following attestation bundles were made for kenso-1.4.0-py3-none-any.whl:
Publisher:
ci.yml on fvena/kenso
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
kenso-1.4.0-py3-none-any.whl -
Subject digest:
cef5919ff8975694ce9ab0421a8c33c13637563a05424ab5bf3f0b01a5fb8c5e - Sigstore transparency entry: 1110604421
- Sigstore integration time:
-
Permalink:
fvena/kenso@1fcf201204b517886786223573aad7a6765d2d2f -
Branch / Tag:
refs/heads/main - Owner: https://github.com/fvena
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yml@1fcf201204b517886786223573aad7a6765d2d2f -
Trigger Event:
push
-
Statement type: