kb-mcp-server
README.md
# kb-mcp-server
[](https://github.com/venkateshds2u/kb-mcp-server/actions/workflows/ci.yml)
[](https://www.python.org/downloads/)
A local-first MCP (Model Context Protocol) server exposing a searchable knowledge
base of notes, backed by SQLite + FTS5. No external API keys required.
Status: **under construction** — this README grows as the project does. See
`ARCHITECTURE.md` for design decisions and `CHANGELOG.md` for what's landed so far.
## Prerequisites
- [uv](https://docs.astral.sh/uv/) (manages the Python interpreter and dependencies —
you do not need Python 3.12 pre-installed, `uv` will fetch it)
## Setup
```bash
cd project-1-mcp-server
uv sync --dev
```
This creates a `.venv/` and installs both runtime and dev dependencies, pinned via
`uv.lock`.
## Running checks locally
```bash
uv run ruff check . # lint
uv run ruff format --check . # format check
uv run mypy # type check (strict)
uv run pytest -v # tests
```
## Running the server
Over stdio (the transport Claude Desktop/Code use):
```bash
uv run kb-mcp-server
```
By default it stores notes in `./data/kb.sqlite3` (override with `KB_DB_PATH`).
It speaks newline-delimited JSON-RPC on stdin/stdout — it's not meant to be
run interactively in a terminal. To poke at it directly, use the
[MCP Inspector](https://modelcontextprotocol.io/legacy/tools/inspector):
```bash
npx @modelcontextprotocol/inspector uv run kb-mcp-server
```
Over Streamable HTTP (for remote clients — requires a bearer token):
```bash
KB_TRANSPORT=http KB_AUTH_TOKEN=$(openssl rand -hex 32) uv run kb-mcp-server
# defaults to http://127.0.0.1:8000/mcp; override with KB_HTTP_HOST/KB_HTTP_PORT
```
Unauthenticated requests to `/mcp` or `/metrics` get `401`. `/health` (no
auth required — for load balancer/k8s liveness probes) checks real database
connectivity, not just that the process is up:
```bash
curl http://127.0.0.1:8000/health
curl -H "Authorization: Bearer $KB_AUTH_TOKEN" http://127.0.0.1:8000/metrics
```
`/metrics` is exposed in Prometheus text exposition format (request counts
by method/path/status, process uptime).
Currently implemented tools: `create_note`, `get_note`, `update_note`,
`delete_note`, `search_notes`.
Currently implemented resources: `notes://recent{?limit}` (recently updated
notes), `notes://{note_id}` (a single note).
Currently implemented prompts: `summarize_note`, `draft_reply`.
## Running with Docker
The image always runs the HTTP transport (stdio doesn't make sense for a
detached container — there's no host process piping its stdin/stdout).
```bash
cp .env.example .env
# edit .env: set KB_AUTH_TOKEN=$(openssl rand -hex 32)
docker compose up --build
```
`docker compose` auto-loads `.env` from the same directory — the exact file
`uv run` also reads locally, so there's one place to set the token either
way. Notes persist in a named volume (`kb-data`) across container restarts.
Without `KB_AUTH_TOKEN` set, `docker compose up` refuses to start at all
(fails at config-interpolation time, before Docker is even invoked) rather
than launching something unauthenticated.
To run the container directly, without compose:
```bash
docker build -t kb-mcp-server .
docker run -d -p 8000:8000 -e KB_AUTH_TOKEN=$(openssl rand -hex 32) \
-v kb-data:/app/data --name kb-mcp-server kb-mcp-server
```
The image runs as a non-root user (uid 1000), ships a `HEALTHCHECK` hitting
`/health`, and forwards `SIGTERM` correctly on `docker stop`/`docker
compose down` (exec-form `CMD`, so the app is PID 1, not a shell wrapping
it).
## Registering with an MCP host
### Claude Code
```bash
claude mcp add kb-notes -s user -- uv run --directory /absolute/path/to/project-1-mcp-server kb-mcp-server
```
`--directory` matters: Claude Code spawns the command without first `cd`-ing
into the project, so `uv run kb-mcp-server` alone (relying on an implicit
cwd) would fail to find `pyproject.toml`. `-s user` registers it for every
project (a personal notes tool isn't tied to any one codebase) — use
`-s local` (the default) to scope it to just the directory you're in, or
`-s project` to check a shared `.mcp.json` into a repo for teammates.
Verify with `claude mcp get kb-notes` — it actually spawns the server and
completes the MCP handshake, so `✔ Connected` means it really works, not
just that the config was written. Then, in a **new** Claude Code session
(MCP servers load at session start, not hot-reloaded into a running one),
ask it to create and search a note.
### Claude Desktop
Add an entry to `claude_desktop_config.json` (macOS:
`~/Library/Application Support/Claude/claude_desktop_config.json`):
```json
{
"mcpServers": {
"kb-notes": {
"command": "uv",
"args": [
"--directory",
"/absolute/path/to/project-1-mcp-server",
"run",
"kb-mcp-server"
]
}
}
}
```
Restart Claude Desktop for it to pick up the change, then look for the
tools under the 🔌 (plug/MCP) icon in a chat.
TDQS
A3.5/5.0
Scored across 5 tools
Disambiguation5/5
Each tool targets a distinct action on a single note resource: create, retrieve, update, delete, and search. There is no overlap or ambiguity; an agent can easily select the correct tool.
Naming Consistency5/5
All tool names follow a consistent verb_noun pattern in snake_case: create_note, get_note, update_note, delete_note, search_notes. The convention is predictable and readable.
Tool Count5/5
With 5 tools, the set is well-scoped for a note management server. It covers essential operations without bloat, and each tool earns its place.
Completeness4/5
The server provides full CRUD plus full-text search, covering the core lifecycle. However, it lacks an explicit 'list all notes' operation, which could be a minor gap for some workflows.
Maintenance
ActivityMaintained
ResponsivenessNo issues