Configuration Reference
Configuration Reference
Every knob gnosis-mcp exposes lives under an environment variable prefixed
GNOSIS_MCP_*. There is no TOML/YAML config file. Philosophy:
- Zero config is the default — running
gnosis-mcp servewith no env set boots SQLite at~/.local/share/gnosis-mcp/docs.dband serves stdio. - Every override is an env var so you can configure inside Docker,
systemd, Claude Desktop / Cursor configs, ordirenvwith the same primitive. - Secrets stay in env — never in the DB, never on disk.
Variables are grouped below by what they control.
Core
GNOSIS_MCP_BACKEND
auto | sqlite | postgres — default auto.
auto inspects GNOSIS_MCP_DATABASE_URL / DATABASE_URL: a postgresql://
URL selects Postgres, anything else (or unset) selects SQLite.
GNOSIS_MCP_DATABASE_URL
Database connection string. Falls back to DATABASE_URL if unset.
- SQLite:
sqlite:///absolute/path/to/docs.db(or leave unset for the default XDG-compliant path). - Postgres: standard libpq URL, e.g.
postgresql://user:pass@host:5432/db.
GNOSIS_MCP_WRITABLE
true | false — default false.
Gate for the three write tools (upsert_doc, delete_doc, update_metadata).
When false, those three tools are withdrawn from tools/list — a
read-only client is never handed a tool it cannot call, and sees six tools
rather than nine, three of which could only ever fail. A call to one of them
then fails as an unknown tool, because as far as the server's advertised
surface is concerned it does not exist. No data is mutated either way.
The in-call check is unchanged: with writes enabled the tools are advertised,
and a call that is still refused for another reason (for example
update_metadata with no fields to update) reports MCP isError: true. Tool
failures carry their payload as the error text of a failed result, not as a
{"error": ...} body inside a successful one.
This changed in v0.15.0. Before that, all nine tools were advertised
regardless and a refused write returned a {"error": ...} payload inside a
successful result — indistinguishable from data, and impossible for a client
to retry or gate on uniformly.
GNOSIS_MCP_LOG_LEVEL
DEBUG | INFO | WARNING | ERROR | CRITICAL — default INFO.
Transport
GNOSIS_MCP_TRANSPORT
stdio | streamable-http | sse — default stdio.
Stdio is the MCP-client default; streamable-http exposes a /mcp endpoint
you can deploy publicly or on a network; sse is a legacy MCP transport.
GNOSIS_MCP_HOST
Default 127.0.0.1. Bind address for the HTTP transports. Use 0.0.0.0
to accept connections from other hosts (and remember to put an auth layer
in front — see GNOSIS_MCP_API_KEY).
GNOSIS_MCP_PORT
Default 8000. Port for the HTTP transport.
Ingestion & chunking
GNOSIS_MCP_CHUNK_SIZE
Default 2000. Minimum 500. Unit: characters (not tokens, not
words).
Target character length for chunks. Chunks never split inside fenced code blocks or markdown tables; splits prefer H2, then H3/H4, then paragraph boundaries.
Rough conversion: 2000 chars ≈ 600 tokens ≈ 300-350 English words.
Why 2000. On a real 558-doc developer-docs corpus with 25 hand-written golden queries, we swept chunk sizes 1000 → 4000 chars in steps. The peak sits on an 1800-2000 char plateau (0.8702 nDCG@10); both smaller (fragments sections, dilutes BM25 term density) and larger (merges unrelated content, same dilution in the other direction) score worse. 2000 is chosen over 1800 as the high end of the plateau — same quality, fewer chunks, faster ingest. Full sweep in bench-experiments-2026-04-18.
Raise it to 3000-4000 for long-form prose (blog posts, ADRs) where sections are naturally bigger. Lower to 1000-1500 for API references or rows-of-tables content where each fact is short and standalone.
GNOSIS_MCP_MAX_DOC_BYTES
Default 50_000_000 (50 MB).
Maximum content size accepted by upsert_doc. Prevents accidentally
attempting to index a 2 GB SQL dump.
GNOSIS_MCP_CONTENT_PREVIEW_CHARS
Default 200. Minimum 50.
Length of the preview slice returned by search_docs. Set larger if you want
chunks returned nearly whole; smaller if you're paying per-token downstream.
GNOSIS_MCP_INGEST_EXCLUDE
Default empty (exclude nothing). Comma-separated root-relative POSIX path prefixes.
Files matching an entry are skipped by ingest, diff and prune. A
trailing slash excludes a whole directory (".internal/audit-logs/"); a bare
entry excludes one file ("llms-full.txt"). The exclusion counts as "not on
disk" for prune, so a file that was indexed before the exclude was
configured is removed on the next prune instead of lingering searchable.
Use this for files that exist on disk but are not documentation — raw audit logs, generated full-text dumps:
GNOSIS_MCP_INGEST_EXCLUDE=".internal/audit-logs/,llms-full.txt" \
gnosis-mcp serve --watch /path/to/knowledge
gnosis-mcp prune /path/to/knowledge # one-time: drop what was indexed earlier
An explicitly empty value (GNOSIS_MCP_INGEST_EXCLUDE=) means "exclude
nothing" and is distinct from unset.
Search
GNOSIS_MCP_SEARCH_LIMIT_MAX
Default 20. Minimum 1.
Hard ceiling for the limit param on search_docs. Clients can ask for
larger numbers but get clamped.
GNOSIS_MCP_MAX_QUERY_CHARS
Default 10_000.
Rejects pathological queries early. Legitimate semantic queries are rarely over a couple hundred characters.
GNOSIS_MCP_RRF_K
Default 60.
Constant in the Reciprocal-Rank-Fusion formula used by hybrid search:
score = Σ 1 / (k + rank_i). Higher k flattens the rank curve and lets
vector scores contribute more relative to BM25. Typical values are 30–120.
GNOSIS_MCP_COLLAPSE_BY_DOC
true | false — default false.
Post-processes the top-K results to keep at most one chunk per document (its highest-scoring one), so a single popular document cannot fill the whole result list. Opt-in so result shapes stay stable for existing callers.
GNOSIS_MCP_FTS5_TITLE_WEIGHT / GNOSIS_MCP_FTS5_CONTENT_WEIGHT
Floats — defaults 10.0 and 1.0. SQLite only.
The bm25() column weights, i.e. how much a title match counts against a body
match. The defaults keep the historical 10:1 ratio; set both to 1.0 for uniform
scoring.
GNOSIS_MCP_MMR_LAMBDA
Float — default 1.0 (disabled).
Below 1.0, the top-K candidates are re-ranked with Maximal Marginal Relevance
(Carbonell & Goldstein, 1998) to trade relevance for diversity: 1.0 is pure
relevance, 0.0 pure diversity, and 0.6 a common middle ground for developer
docs. Requires an active embedder — it falls back to the original order when
embedding fails.
GNOSIS_MCP_SEARCH_FUNCTION
(Postgres only.) Name of a user-defined function that search_docs delegates
to instead of the built-in path — useful for plugging in experimental ranking
without forking the server. It is called as:
SELECT * FROM your_function(
p_query_text := $1::text, p_embedding := $2::vector,
p_categories := $3::text[], p_limit := $4::integer)
p_embedding is NULL when no embedding is available and p_categories is
NULL unless a category filter is set, so give both defaults. It must return the
same columns as the built-in search functions:
(file_path text, title text, content text, category text, combined_score double precision).
Embeddings
GNOSIS_MCP_EMBED_PROVIDER
local | openai | ollama | custom — unset by default (no auto-embedding).
local— ONNX Runtime CPU inference. Requires the[embeddings]extra.openai— OpenAI-compatible HTTP API.ollama— an Ollama-compatible HTTP API.custom— any OpenAI-schema HTTP endpoint (setGNOSIS_MCP_EMBED_URL).
GNOSIS_MCP_EMBED_MODEL
Model name. The general default is text-embedding-3-small (OpenAI, 1536-dim).
When GNOSIS_MCP_EMBED_PROVIDER=local, the default switches to
MongoDB/mdbr-leaf-ir (384-dim, 23 MB quantized, Apache 2.0, auto-downloaded
on first run with an HTTPS + SHA-256 checksum assertion).
GNOSIS_MCP_EMBED_DIM / GNOSIS_MCP_EMBEDDING_DIM
Output dimension. Both spellings accepted. When unset, the server asks the provider to report it once at start-up.
GNOSIS_MCP_EMBED_URL
Custom / remote provider endpoint (OpenAI-schema /embeddings POST).
GNOSIS_MCP_EMBED_API_KEY
Bearer token for the remote provider.
GNOSIS_MCP_EMBED_BATCH_SIZE
Default 50. Minimum 1. Balances provider rate limits against ingest
throughput.
Reranking
GNOSIS_MCP_RERANK_ENABLED
true | false — default false.
Opt-in cross-encoder reranker (22M-param ONNX) applied to the top candidates
from search_docs before returning. Requires the [reranking] extra.
Typical cost: ~20 ms per query for the default top-20 pool on laptop CPU.
GNOSIS_MCP_RERANK_MODEL
Default cross-encoder/ms-marco-MiniLM-L6-v2. The cross-encoder to download
and run. It must be a genuine cross-encoder (a BertForSequenceClassification
style model that scores a query/passage pair) — pointing it at an embedding model
produces no usable scores. A model that cannot be fetched is reported at startup
and searches then return unranked results, so verify it on your corpus.
GNOSIS_MCP_RERANK_POOL
Integer — default 20. How many candidates are fetched and re-scored before
the top limit are returned. A larger pool is more accurate and slower.
Web crawl
GNOSIS_MCP_CRAWL_EXTRACT_TIMEOUT_S
Default 30. Seconds before we abandon the HTML-to-markdown extraction
for a given page. Prevents pathological pages from freezing the crawl loop.
Webhooks
GNOSIS_MCP_WEBHOOK_URL
Fires a fire-and-forget POST on every write tool. Body is a small JSON
envelope: {tool, path, ts}. Useful for invalidating downstream caches.
GNOSIS_MCP_WEBHOOK_TIMEOUT
Default 5. Seconds. Minimum 1.
GNOSIS_MCP_WEBHOOK_ALLOW_PRIVATE
true | false — default false.
By default the webhook target must resolve to a public IP. Requests to
private, loopback, link-local, multicast, or reserved addresses are refused
with a warning log. Set true for intentional loopback CI setups.
REST API
Enable with the --rest flag on gnosis-mcp serve or GNOSIS_MCP_REST=true.
Lives alongside MCP on the same HTTP port. See rest-api.md
for the endpoint reference.
GNOSIS_MCP_REST
true | false — default false.
GNOSIS_MCP_API_KEY
Optional. When set, every endpoint (except /health) requires
Authorization: Bearer <key>. Comparison is timing-safe.
GNOSIS_MCP_PUBLIC_PATHS
Not implemented — reading this variable has no effect. It is documented here only so the absence is explicit.
/health is the one unauthenticated path, always. Every other route,
including anything under /api/ and POST /v1/embed, requires
Authorization: Bearer <key> whenever GNOSIS_MCP_API_KEY is set. There is
no way to add a second public path by configuration today.
The setting was documented in the pre-launch docs commit but the env-var
read was never written: GnosisMcpConfig has no public_paths field, and
the auth middleware is constructed as ApiKeyMiddleware(app, config.api_key)
with no public_paths argument, so it falls back to its built-in
("/health",) default. (The middleware does accept a public_paths
parameter, so the hook exists for a future release — it is simply never
supplied.) If you need extra probes to bypass auth, terminate them at your
reverse proxy rather than at gnosis-mcp.
GNOSIS_MCP_CORS_ORIGINS
Comma-separated origins, or *. No CORS response headers unless set.
Access log
GNOSIS_MCP_ACCESS_LOG
true | false — default true.
When enabled, records which documents are retrieved via search_docs
(top 3 results) and get_doc. Used by get_context to surface
frequently-read documentation. Writes to search_access_log table; set to
false to disable tracking entirely.
Each row also carries the MCP client that made the call (from the session's
initialize handshake) and the token counts that back savings;
usage reads all of it, including misses — a search_docs
call that matched nothing is logged with an empty file_path, so a query the
index could not answer is still a row.
If the table predates those columns, init-db retrofits them (ALTER TABLE … ADD COLUMN IF NOT EXISTS) on the next run. Until it does, logging succeeds with
no error while client/token attribution stays empty — silently. Re-running
init-db after an upgrade is always safe: every statement is idempotent.
Postgres-specific
GNOSIS_MCP_SCHEMA
Default public. Alternate schema for all gnosis-mcp tables.
GNOSIS_MCP_CHUNKS_TABLE
Default documentation_chunks. Single name or comma-separated list —
with multiple tables, search queries use UNION ALL. All tables must share the
same schema (identical column names and types), and writes (ingest,
upsert_doc, delete_doc, update_metadata) target the first table in the
list.
GNOSIS_MCP_LINKS_TABLE
Default documentation_links.
GNOSIS_MCP_POOL_MIN / GNOSIS_MCP_POOL_MAX
asyncpg connection-pool bounds. Defaults 1 / 3.
Column overrides (GNOSIS_MCP_COL_*)
When connecting to an existing schema with non-standard column names, map each field:
| Env var | Logical column |
|---|---|
GNOSIS_MCP_COL_FILE_PATH |
file_path |
GNOSIS_MCP_COL_CHUNK_INDEX |
chunk_index |
GNOSIS_MCP_COL_TITLE |
title |
GNOSIS_MCP_COL_CATEGORY |
category |
GNOSIS_MCP_COL_CONTENT |
content |
GNOSIS_MCP_COL_AUDIENCE |
audience |
GNOSIS_MCP_COL_TAGS |
tags |
GNOSIS_MCP_COL_EMBEDDING |
embedding |
GNOSIS_MCP_COL_TSV |
search_vector |
GNOSIS_MCP_COL_SOURCE_PATH |
source_path (links) |
GNOSIS_MCP_COL_TARGET_PATH |
target_path (links) |
GNOSIS_MCP_COL_RELATION_TYPE |
relation_type (links) |
Every identifier is validated against ^[a-zA-Z_][a-zA-Z0-9_]*$ at startup
to prevent SQL injection via config.
Precedence
- Explicit env var.
- Derived default (e.g.
GNOSIS_MCP_BACKEND=autoinferring from URL). - Hard-coded default.
There is no file-based override layer. Restart the server to pick up env changes.