kb-mcp-server
Exposes a /metrics endpoint in Prometheus text exposition format, reporting request counts by method/path/status and process uptime for scraping by Prometheus.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@kb-mcp-serversearch my notes for meeting recaps"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
kb-mcp-server
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 (manages the Python interpreter and dependencies — you do not need Python 3.12 pre-installed,
uvwill fetch it)
Related MCP server: Obsidian MCP Server
Setup
cd project-1-mcp-server
uv sync --devThis creates a .venv/ and installs both runtime and dev dependencies, pinned via
uv.lock.
Running checks locally
uv run ruff check . # lint
uv run ruff format --check . # format check
uv run mypy # type check (strict)
uv run pytest -v # testsRunning the server
Over stdio (the transport Claude Desktop/Code use):
uv run kb-mcp-serverBy 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:
npx @modelcontextprotocol/inspector uv run kb-mcp-serverOver Streamable HTTP (for remote clients — requires a bearer token):
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_PORTUnauthenticated 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:
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).
cp .env.example .env
# edit .env: set KB_AUTH_TOKEN=$(openssl rand -hex 32)
docker compose up --builddocker 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:
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-serverThe 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
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):
{
"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.
Available Tools
5 toolscreate_noteC
Create a new note with a title and body, and return the saved note.
| Name | Required | Description | Default |
|---|---|---|---|
| body | Yes | ||
| title | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | |
| body | Yes | |
| title | Yes | |
| created_at | Yes | |
| updated_at | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full behavioral burden, and it mostly doesn't. It discloses only that the saved note is returned; nothing about auth/permissions, failure modes, or that this is a persistent mutation. That's thin for a write tool with zero annotation coverage.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single front-loaded sentence with no padding. The clause about returning the saved note is slightly redundant given an output schema exists, but overall it is tight and well-ordered.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The tool is simple (2 required string params) and an output schema covers the return value, so the bar is low. Still, for a mutation with no annotations and no parameter documentation, the description leaves behavioral essentials (permissions, error behavior, whether the note persists) unaddressed.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description should compensate, but it only echoes the parameter names (title, body) without adding meaning. Length limits, constraints, and any format expectations remain unstated in prose even though the schema encodes min/max lengths.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (Create) and resource (note) plus the required inputs and that the result is returned. The action is unambiguously distinct from get_note/update_note/delete_note, though the description never names or contrasts those siblings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
No when-to-use guidance and no exclusions. With update_note as a sibling, the agent gets no explicit signal that this tool is for brand-new notes rather than modifying existing ones; usage is only inferable from the name and verb.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
delete_noteC
Delete a note by its id.
| Name | Required | Description | Default |
|---|---|---|---|
| note_id | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full behavioral burden. For a destructive operation it says nothing about irreversibility, whether the deletion is soft or hard, permission requirements, or error behavior for a nonexistent id.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single front-loaded sentence with no wasted words. Terseness here is efficiency rather than padding, though the brevity borders on under-specification for a destructive tool.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need not be explained. However, for a one-parameter destructive tool with zero annotations and zero schema description coverage, the description is missing the irreversibility and permission context an agent needs to invoke it safely.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Only one parameter, and schema description coverage is 0%, so the schema gives no format or source hints for note_id. The description adds that the id identifies the note to delete, but no format, origin, or example, so it only marginally compensates for the coverage gap.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb ('Delete') and resource ('a note') with the keying parameter identified. It doesn't explicitly distinguish itself from siblings like update_note or get_note, but the destructive verb makes the distinction inferable.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
No when-to-use guidance, no prerequisites, no exclusions. There is no warning that this is a permanent removal versus a soft delete, and no mention of what the caller needs to have done beforehand (e.g. obtaining the note_id).
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_noteB
Retrieve a single note by its id.
| Name | Required | Description | Default |
|---|---|---|---|
| note_id | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | |
| body | Yes | |
| title | Yes | |
| created_at | Yes | |
| updated_at | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries full behavioral burden, and it discloses almost nothing beyond the implied read nature of 'Retrieve'. It does not state permission requirements, behavior on a missing/invalid id, or whether deleted notes are visible.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single tight sentence with the resource and lookup key front-loaded and no filler. It is efficient, though terse enough that it forgoes useful context.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need not be described, and one identifier parameter is a simple contract. Still, with zero annotations and no schema parameter description, the definition omits error/not-found behavior and authorization context that an agent would want before calling.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the schema does not explain note_id; the description partially compensates by identifying it as the note's id. It adds no format, type, or sourcing detail (e.g., where the id comes from), leaving the parameter only half-documented.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb ('Retrieve') and resource ('a single note') plus the lookup key ('by its id'), so an agent can distinguish it from list/search-style siblings. It stops short of explicitly contrasting itself with search_notes, which would be the natural source of confusion.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is only implied: 'by its id' signals this is for cases where the identifier is already known, contrasting implicitly with search_notes. There is no explicit statement of when to prefer this over search_notes or what happens if the id is unknown.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_notesA
Full-text search over note titles and bodies, ranked by relevance. Supports FTS5 syntax: quote a phrase for an exact match, combine terms with AND/OR/NOT, or prefix-match with an asterisk (e.g. kaf*).
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | ||
| query | Yes | ||
| offset | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| items | Yes | |
| limit | Yes | |
| total | Yes | |
| offset | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden, and it does disclose meaningful behavior: relevance-ranked results and supported FTS5 query semantics (phrase quoting, AND/OR/NOT, asterisk prefix matching) with a concrete example. It omits result ordering details beyond relevance and any pagination/limit behavior.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two tight sentences, front-loaded with the core purpose before the syntax detail. Every clause adds value; no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need not be explained. For a read-only search tool with three parameters, the core query semantics are well covered; only limit/offset behavior is unaddressed, a minor gap.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate. It richly documents the required query parameter's syntax, which is the critical semantic. The limit/offset parameters are left to the schema, but their names, defaults, and min/max bounds make them largely self-explanatory.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('Full-text search over note titles and bodies') and specifies ranking behavior. It is immediately distinguishable from the CRUD siblings get_note/create_note/update_note/delete_note.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
No explicit when-to-use or when-not-to-use guidance and no sibling is named as an alternative. Usage is only implied by the verb 'search' versus the CRUD siblings.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
update_noteC
Replace an existing note's title and body.
| Name | Required | Description | Default |
|---|---|---|---|
| body | Yes | ||
| title | Yes | ||
| note_id | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | |
| body | Yes | |
| title | Yes | |
| created_at | Yes | |
| updated_at | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full behavioral burden. 'Replace' usefully signals full overwrite semantics rather than a merge, but it says nothing about required permissions, what happens on a nonexistent note_id, whether changes are reversible, or any rate/size constraints beyond the schema.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single front-loaded sentence with no filler; every word earns its place. Brevity is appropriate for a simple three-parameter tool, though the terseness coincides with the informational gaps noted elsewhere.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need not be described, but for a mutation tool with zero annotation coverage the description should say more about prerequisites and side effects. As written it is incomplete relative to the tool's write semantics.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0% and all three parameters are required with constraints (minLength/maxLength) that the description never mentions. The description names title and body, mapping to two params, but note_id is never referenced and no format or value guidance is given.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb ('Replace') and resource ('note') plus the fields affected (title and body), so it is clearly distinguishable from get_note, create_note, delete_note, and search_notes. It stops short of explicitly naming how it differs from siblings or referencing them.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
No when-to-use guidance, no mention of prerequisites such as the note existing, and no routing to alternatives like create_note or get_note. The agent must infer usage entirely from the verb.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
5 tool updates
v0.1.0- First observed
create_note - First observed
delete_note - First observed
get_note - First observed
search_notes - First observed
update_note
TDQS
Scored across 5 tools
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.
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.
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.
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
Related MCP Connectors
Personal context for every AI: search, read, and write back to your private Markdown library.
Google Keep-style notes app with an MCP server for AI agents to read/write notes.
Personal wiki and memory layer for AI assistants. Persistent, structured memory across sessions.
A self-improving memory layer. Your memory, notes, tasks and goals, remembered everywhere.
Related MCP Servers
- FlicenseBqualityDmaintenanceEnables indexing and retrieving notes with full-text search using SQLite, plus building knowledge graphs to find relationships between concepts. Supports natural language note management, tagging, and semantic connections.16-
- AlicenseAqualityDmaintenanceEnables AI assistants to interact with Obsidian vaults for creating, reading, searching, and managing notes, daily notes, TODOs, session reports, and backlinks through both stdio and HTTP/SSE transports.102,7784MIT
- FlicenseNot gradedqualityDmaintenanceEnables to create notebooks and notes with tags, and perform full-text search across notes using FTS5 syntax, all stored locally in SQLite.-
- FlicenseAqualityDmaintenanceA lightweight, intelligent note-organizing server that acts as an AI-powered personal memory vault for capturing, organizing, and retrieving insights using FastMCP and SQLite.82-