AtlatestRepositoryfolio
1
# Shared HTTP server3
Run one Folio process for multiple local MCP clients:5
```sh6
FOLIO_ROOT="$HOME/folio" folio serve --http 18765 \7
--token-file "$HOME/.config/folio/http.token"8
```10
The listener binds only `127.0.0.1`. Clients use `/mcp` with an11
`Authorization: Bearer TOKEN` header. The token file must have no group or12
other permissions, contain one printable ASCII token of at least 32 characters,13
and stay outside client configuration files. Unauthenticated requests return 40114
before protocol dispatch. The five-minute HTTP timeout applies to request15
parsing and idle connections. Dispatched tool streams leave that timeout16
sweep: there is no server-side tool deadline, and a hung tool can hold its17
socket indefinitely. Clients should allow a six-minute tool timeout.18
`folio/rebuild-index` is refused immediately over HTTP; run explicit full19
rebuilds through a separate stdio maintenance session. An initial HTTP start20
with an empty or upgraded index can take several minutes before it listens.21
Wait for readiness before connecting clients.23
Stdio remains the default. `--http` and `--stdio` are mutually exclusive.24
`--web` and `--web-port PORT` are accepted with one stderr deprecation warning25
and ignored; the old local note viewer has been removed.27
## Storage and indexing29
Validated HTTP tool calls run in separate cooperative tasks. A writer waiting30
for another process's store lock leaves independent reads free to complete.31
CPU-bound calls still share one thread; they are not preempted. Mutating tool32
handlers are serialized through their index flush, including inbox reads that33
may backfill ids. Other read tools do not enter that writer queue.34
Tools taking over ten milliseconds allow socket polling before JSON encoding35
with a one-millisecond cooperative pause; faster tools can reply immediately.36
Cold file-cache fills and task-block parsing also pause between work units37
after about ten milliseconds, so a first status, inbox or task-notes call can38
populate its caches while independent reads proceed. Cache hits bypass these39
checkpoints; a fingerprint recheck after a pause prevents caching a value40
whose file changed meanwhile. Individual native operations still occupy the41
thread until they return, so this is not a hard response-time bound.42
Note listings skip unused full-text snippets, and43
updates locate existing full-text rows through their indexed names.45
Note and project mutations use the cross-process SQLite store lock. Index46
maintenance never takes that lock: each indexed document is replaced in its47
own transaction. A per-connection channel mutex keeps concurrent index tasks48
from sharing a transaction, and a fingerprint captured before reading lets a later census49
repair stale results after concurrent edits. Files are replaced atomically. Read-only50
tools retain their direct read path. A failed index refresh after a saved write51
is logged without turning that successful write into a failed tool call.53
HTTP index reads use a separate SQLite connection from census and writes, so54
they cannot see that connection's uncommitted rows. A read concurrent with a55
write may finish first and see the previous committed state. A read sent after56
the write reply sees its committed index update under the existing write-through57
and census-retry rules. SQLite consistency is per query and Markdown replacement58
is atomic per file; tools have no global snapshot across files and index queries.59
Stdio retains one connection and the same cross-process writer coordination.61
HTTP tool replies are ordinary JSON-RPC JSON documents sent with chunked62
framing and `Connection: close`, using one connection per tool call with no63
pipelining after a `tools/call`. Early validation retains its HTTP errors; an64
unexpected failure after response headers are sent becomes a JSON-RPC internal error carrying the same65
request id. Clients must consume the complete body before decoding it.67
A metadata census runs every 15 seconds, reading content only for changed files.68
Signatures include inode, size and nanosecond timestamps. Files that cannot be69
read or parsed are retried when their fingerprint changes; database failures70
remain retryable on the next census. The initial census populates a new index,71
and `folio/rebuild-index` explicitly rebuilds all documents in stdio mode.73
## Supervision and clients75
[The Shepherd example](../examples/folio.scm) returns a user-service definition76
and a log-rotation service. It creates a private random token on first start,77
respawns Folio, and uses the XDG configuration/state directories. Set the78
executable and data-root arguments for your installation. Reuse an existing79
Shepherd log-rotation service rather than registering a second one.81
For clients with an optional HTTP configuration, probe the unauthenticated MCP82
URL at launch and expect 401. If the probe fails or returns another status,83
warn and generate the usual stdio configuration. Read the token into the client84
process environment; keep only its variable name in generated configuration.86
## Development status88
The 0.3.4 lock uses published sigil-json 0.16.2 (less encoding CPU), sigil-mcp89
0.18.4 (opt-in deferred tools) and sigil-http 0.18.8, retaining the pinned90
0.22.15 runtime family. Release builds and qualification use that public lock91
without dependency overrides. `dev-redirects.sgl` is optional development92
configuration, active only when explicitly selected through the CLI or93
`SIGIL_REDIRECTS`; do not enable it for release qualification.