NIB knowledge base — pgvector-backed MCP server for semantic search over infrastructure docs
2.9K
Knowledge-base server for NIB (Neuro Infrastructure Builder), speaking the Model Context
Protocol. It stores your infrastructure documentation in PostgreSQL with pgvector, embeds it
through an OpenAI-compatible /embeddings endpoint, and answers semantic search queries from any
MCP client — the NIB agent, or your own.
The point is specificity. A planning agent that knows the general shape of Kubernetes still cannot tell you which cluster your staging ingress lives on, which registry your images come from, or why that one service is pinned to an old node pool. This is where that knowledge goes, and how the agent retrieves it while planning.
It is one of four images: nib-kb (this one), nib-backend
(API and agent orchestrator), nib-frontend (web UI)
and nib-agent (the coding-agent runner).
The server exposes one tool:
knowledge_search — embeds a natural-language query and returns the closest kb_chunks rows
from the named collection, by cosine similarity in pgvector.
| Parameter | Type | Required | Notes |
|---|---|---|---|
query | string | yes | Natural-language search text |
collection | string | yes | kb_collections.name |
limit | number | no | Maximum hits, with a server-side cap |
Two transports:
-transport http -http-addr :8081 -http-path /mcp (the image default), for
clients that connect over the network. Add -http-stateless to run without session tracking.-transport stdio, for a client that spawns the binary as a child process.Inside NIB the agent reaches this over the internal network at http://kb-mcp:8081/mcp, registered
as an MCP server in data/mcp.json. Alongside search, NIB agents read the current source document
with get_kb_document and write a collection back with update_kb (those tools live in the
backend); the build-knowledge-base skill drives the whole round trip — hand it a project name
and a list of repositories and it fills the shipped skeleton in from what the repositories actually
say, rather than from what someone remembered to write down last year.
docker run -d --name nib-kb \
-p 8081:8081 \
-e DATABASE_URL='postgres://nib:nib@postgres:5432/nib?sslmode=disable' \
-e OPENROUTER_API_KEY="$LLM_API_KEY" \
-e EMBEDDINGS_BASE_URL=https://api.openai.com/v1 \
javdet/nib-kb:latest
MCP endpoint: http://<host>:8081/mcp. The database must have the pgvector extension available;
the NIB backend creates and migrates the schema.
The whole stack comes up together with the repository's Compose file or Helm chart — see
nib-backend.
| Variable | Purpose |
|---|---|
DATABASE_URL | Postgres DSN. Required unless you pass -dsn or a -config file with knowledge_base.uri |
OPENROUTER_API_KEY | API key for the embeddings endpoint when -provider openrouter |
EMBEDDINGS_BASE_URL | OpenAI-compatible API base, e.g. https://api.openai.com/v1 or https://openrouter.ai/api/v1 |
GOOGLE_API_KEY / GEMINI_API_KEY | API key when -provider google |
GOOGLE_API_BASE_URL | Google Generative Language API base override |
HTTP_REFERER / OPENROUTER_APP_TITLE | Optional OpenRouter attribution headers |
Despite the name, -provider openrouter is the CLI's label for any OpenAI-compatible
/embeddings client — OpenAI itself, OpenRouter, or a self-hosted gateway. Point
EMBEDDINGS_BASE_URL wherever you like. -provider google selects the Generative Language API
instead.
kb serve-mcp flags| Flag | Default | Purpose |
|---|---|---|
-transport | stdio (image overrides to http) | stdio or http (streamable HTTP) |
-http-addr | :8081 | Listen address for -transport http |
-http-path | /mcp | Endpoint path |
-http-stateless | off | Serve streamable HTTP without session tracking |
-dsn | — | Postgres DSN, overriding DATABASE_URL and config |
-config | — | YAML config to read knowledge_base.uri from |
-provider | openrouter | openrouter (OpenAI-compatible) or google — must match how the collection was ingested |
-model | — | If set, every searched collection must use this embedding_model; otherwise the collection row supplies it |
-timeout | 120s | HTTP timeout for embedding requests |
-embeddings-base-url | — | OpenAI-compatible base URL |
-google-base-url | — | Google API base URL |
The image's default command is:
kb serve-mcp -transport http -http-addr :8081 -http-path /mcp
Override it with command: in Compose or args: in Kubernetes.
Embedding models must match exactly. A collection records the model it was embedded with, and search compares that string against the model in use. Change the embedding model and the old collection stops matching — re-ingest it rather than expecting a silent migration.
The same binary ingests. It chunks the input, embeds each chunk in batches, and writes
kb_collections / kb_chunks:
docker run --rm -i \
-e DATABASE_URL='postgres://nib:nib@postgres:5432/nib?sslmode=disable' \
-e OPENROUTER_API_KEY="$LLM_API_KEY" \
-e EMBEDDINGS_BASE_URL=https://api.openai.com/v1 \
--entrypoint kb javdet/nib-kb:latest \
ingest -collection myproject -model text-embedding-3-small -replace < runbook.md
| Flag | Default | Purpose |
|---|---|---|
-collection | — | Collection name (required) |
-model | — | Embedding model id (required) |
-chunk-size | 512 | Maximum runes per chunk |
-chunk-overlap | 64 | Rune overlap between consecutive chunks, so a fact split across a boundary is still findable |
-embed-batch | 32 | Texts per embedding API request |
-insert-batch | 256 | Rows per database insert batch |
-metric | cosine | Distance metric label stored on the collection |
-replace | off | Delete existing chunks with the same source_uri before inserting — this is what makes re-ingest idempotent instead of duplicating |
Files are passed as arguments, or the text is piped on stdin. In normal NIB use you do not run this
by hand: the UI and the build-knowledge-base skill drive ingestion for you.
CGO_ENABLED=0) on gcr.io/distroless/static-debian12:nonroot.nonroot:nonroot. No shell, no package manager, no busybox — the attack surface is
the binary and nothing else. Worth knowing before you plan to docker exec into it: you cannot.8081. No healthcheck is baked in — the MCP endpoint expects a protocol handshake
rather than a plain GET, so probe it at the TCP level (a Kubernetes tcpSocket probe on 8081).latest · vX.Y.Z (release, matching the repository's VERSION file) · <git-sha> (exact commit).
Built for linux/amd64 and linux/arm64.
Pin vX.Y.Z in production and keep backend, frontend and kb on the same tag — they are released
together from one repository and share the database schema.
docs/knowledgebase/ in the repositoryLICENSE before deploying this in a commercial setting.Content type
Image
Digest
sha256:fbab6d4d2…
Size
5.4 MB
Last updated
15 days ago
docker pull javdet/nib-kb