Skip to content

Deployment

You run one mfs-server; everything else points at it. This page is the operator's guide to the shapes that server can take — from a local server on your laptop to a container to a Kubernetes split — and how a client reaches each one.

The server installs from PyPI (uv tool install mfs-server) or runs from a container you build from the repository. For the credential boundary see Auth and secrets; for model/provider setup see Providers and processing; for backup and restore see Storage and backup.

The shapes

Topology What runs Best for State lives in
Local server mfs-server run + the mfs CLI on one host Local use, evaluation, connector development $MFS_HOME (default ~/.mfs)
Docker all-in-one One container running mfs-server run An isolated, repeatable server a /data volume
Compose all-in-one The same container wrapped in Compose Repeatable container startup the mfs-data volume at /data
Kubernetes api/worker Separate API and worker Deployments + a Service Horizontal scale Postgres, object storage, managed Milvus/Zilliz
flowchart LR
  subgraph host["Client host"]
    cli["mfs CLI"]
  end
  subgraph server["Server runtime"]
    api["mfs-server API"]
    worker["inline worker or worker pod"]
    state["metadata · cache · vectors"]
  end
  cli -->|HTTP /v1 + bearer token| api
  api --> worker
  worker --> state

The first three are all-in-one: one process (or container) holds the API, the worker, and local state. The Kubernetes split is the scale-out target — separate API and worker pods against externalized state — and is the direction the architecture is built for. Use an all-in-one server for everyday operation; reach for the chart when you actually need to scale.

Persisted state

The server keeps everything it owns under one root: $MFS_HOME (default ~/.mfs) for a source run, /data in the container images.

State File Why it matters
Server config server.toml Written by mfs-server setup.
API token server.token Generated when none is configured; clients need the same token.
Metadata DB metadata.db Connectors, objects, jobs (SQLite default).
Transformation cache transformation_cache.db Cached model outputs, so re-syncs don't recompute.
Artifact cache cache/ Converted document blobs.
Vector DB milvus.db Milvus Lite, when no remote endpoint is configured.
ONNX model cache onnx-cache/ The default embedding model, preloaded at startup.

Mount /data for containers

Mount /data to a persistent volume. Without it, the metadata, vectors, caches, and the generated token all vanish when the container is removed.

Auth and tokens

mfs-server run and mfs-server api enable bearer auth by default: if no token is configured they reuse or create $MFS_HOME/server.token. Set MFS_API_TOKEN in the server environment to pin a known token. GET /healthz is always unauthenticated; every /v1 endpoint needs the token when auth is on.

Client / server placement How the client gets the token
CLI and server share $MFS_HOME The CLI reads $MFS_HOME/server.token automatically — nothing to set.
CLI → container server Export MFS_API_URL and MFS_API_TOKEN; read the token from /data/server.token or start the container with a known MFS_API_TOKEN.
Direct HTTP client Send Authorization: Bearer <token> on /v1.
Kubernetes One shared API token for all API replicas, from the configured secret.

Local server

uv tool install mfs-server                       # base server
uv tool install "mfs-server[all-connectors]"     # + every connector's SDK

mfs-server setup                     # optional: write $MFS_HOME/server.toml
mfs-server run                       # binds 127.0.0.1:13619

To run from a checkout instead — for connector development or local changes — uv sync in server/python and prefix the commands with uv run (see Development).

The first-run defaults are fully local and need no API key: ONNX embeddings (gpahal/bge-m3-onnx-int8, 1024 dims), Milvus Lite, SQLite, a local artifact cache, VLM off, and an auto-generated bearer token. Verify from another terminal:

mfs status
curl http://127.0.0.1:13619/healthz

For same-host paths the server reads the path directly (mfs add /path/to/project). Use upload mode only when the server process can't see the path you pass.

Docker all-in-one

Build the image from the repository root and run it with a persistent /data volume:

docker build -f deployments/docker/Dockerfile \
  --build-arg EXTRAS="[all-connectors]" -t mfs-server .

docker run -d --name mfs-server -p 13619:13619 -v mfs-data:/data mfs-server

Pin a known token, or point the server at Zilliz Cloud / a remote Milvus, with environment variables:

docker run -d --name mfs-server -p 13619:13619 -v mfs-data:/data \
  -e MFS_API_TOKEN="$MFS_API_TOKEN" \
  -e MILVUS_URI="$ZILLIZ_URI" \
  -e MILVUS_TOKEN="$ZILLIZ_TOKEN" \
  mfs-server

Connect the host CLI to the container:

export MFS_API_URL=http://127.0.0.1:13619
export MFS_API_TOKEN="$(docker exec mfs-server cat /data/server.token)"
mfs status

Indexing host paths from a container

A container can't read an arbitrary host path unless you mount it. Choose a mode deliberately:

Situation Command
The path exists only on the host mfs add --upload /path/on/host
The path is mounted into the container mfs add --no-upload /path/in/container
Resend every file mfs add --force-upload /path/on/host
Bytes already staged, force a full re-index mfs add --force-index /path/on/host

After an upload the registered connector identity may be the uploaded URI rather than the bare host path — mfs connector list / inspect TARGET shows the real target before you scope a search.

Docker Compose all-in-one

The Compose file builds the same image, runs mfs-server run --bind 0.0.0.0:13619, exposes port 13619, sets MFS_HOME=/data, and persists the mfs-data volume:

docker compose -f deployments/compose/docker-compose.yml up --build
export MFS_API_URL=http://127.0.0.1:13619
export MFS_API_TOKEN="$(docker compose -f deployments/compose/docker-compose.yml \
  exec -T mfs-server cat /data/server.token)"
mfs status

To pin a known token, export MFS_API_TOKEN before up. The upload rules from the Docker section apply unchanged.

Kubernetes api/worker

The chart under deployments/helm/mfs renders an API Deployment (mfs-server api), a Worker Deployment (mfs-server worker --concurrency auto), and an API Service. Probes use unauthenticated GET /healthz. This shape expects externalized state — Postgres, object storage, and a managed Milvus/Zilliz endpoint.

helm lint deployments/helm/mfs
helm template mfs deployments/helm/mfs --set search.uri=https://xxx.zillizcloud.com

It expects a secret (default mfs-secrets) with these keys:

Key Used for
api-token Shared API bearer token for all replicas
zilliz-token Zilliz / Milvus token
openai-api-key OpenAI key, when OpenAI-backed features are configured
kubectl create secret generic mfs-secrets \
  --from-literal=api-token="$MFS_API_TOKEN" \
  --from-literal=zilliz-token="$ZILLIZ_TOKEN" \
  --from-literal=openai-api-key="$OPENAI_API_KEY"

kubectl port-forward svc/mfs-api 13619:13619
curl http://127.0.0.1:13619/healthz

Native acceleration (optional)

A few server hot paths — the gitignore directory walk, parallel content hashing, linear grep, and tail — have an optional Rust extension (mfs-server-rs, built from server-rs/). It is never required: when the wheel isn't installed, the server uses an equivalent pure-Python path and behaves identically, just slower on large inputs. So treat it as a performance knob, not a dependency.

It is not published to PyPI. Build it locally and install it into the same environment as the server.

In the Docker image, pass --build-arg ACCEL=1 — a separate build stage compiles the wheel with a Rust toolchain and installs it; the default (ACCEL=0) ships a pure-Python image and never pulls the toolchain:

docker build -f deployments/docker/Dockerfile \
  --build-arg ACCEL=1 --build-arg EXTRAS="[all-connectors]" -t mfs-server .

When running from a checkout, build the extension with maturin (needs a Rust toolchain) into the server's environment:

cd server-rs
uv run --project ../server/python maturin develop --release

The server detects it automatically on the next start — nothing to configure.

Environment variables

Variable Effect Default
MFS_HOME Server home for config, token, SQLite, caches, Milvus Lite, ONNX cache. ~/.mfs (containers: /data)
MFS_SERVER_CONFIG Explicit config-file path, after the --config flag. falls back through ./server.toml, $MFS_HOME/server.toml, /etc/mfs/server.toml
MFS_API_TOKEN Server: pin the bearer token. CLI: token for a remote/container server. server generates $MFS_HOME/server.token if unset
MFS_API_URL CLI: point at a non-default endpoint. http://127.0.0.1:13619
MILVUS_URI Milvus Lite path, or a Milvus/Zilliz endpoint. $MFS_HOME/milvus.db
MILVUS_TOKEN Milvus/Zilliz token. empty
ZILLIZ_URI / ZILLIZ_TOKEN / ZILLIZ_API_KEY Accepted fallbacks for the Zilliz endpoint and token. used when the MILVUS_* form is unset
OPENAI_API_KEY Needed only when an OpenAI-backed embedding/VLM/summary provider is selected. unused on the default local path
MFS_METADATA_DSN Switch metadata to Postgres. SQLite under $MFS_HOME
MFS_TX_CACHE_DSN + MFS_TX_CACHE_PG Put the transformation cache on Postgres. default backend
MFS_SUMMARY_ENABLED Toggle directory summaries. per config

Health ladder

Climb this to localize a problem — process, then auth, then state, then indexing:

Check Command Healthy signal
Process curl …/healthz {"status":"ok"}
Auth + server info curl -H "Authorization: Bearer $MFS_API_TOKEN" …/v1/server/info version, machine id, namespace
CLI connection mfs status JSON with connectors and jobs
Jobs mfs job list recent job records
Connectors mfs connector list registered connector URIs
Search & browse mfs search QUERY TARGET, mfs cat PATH --range 1:20 hits and readable content
Minimal all-in-one smoke test
mkdir -p /tmp/mfs-quickstart
cat > /tmp/mfs-quickstart/README.md <<'EOF'
MFS uses a Rust CLI and a Python server.
The default server listens on 127.0.0.1:13619.
EOF

export MFS_API_URL=http://127.0.0.1:13619
mfs status

mfs add /tmp/mfs-quickstart          # or: mfs add --upload ... for a container/remote server
mfs job show JOB_ID

mfs search "default endpoint" /tmp/mfs-quickstart --top-k 5
mfs cat /tmp/mfs-quickstart/README.md --range 1:20