Same task: fetch users from a REST API and return markdown. From the peer-reviewed paper, measured on live experiments:
|
LiveFolders — folder.yaml (10 lines)
name: users
description: List users from the mock API.
files:
- name: list
type: read_invoke
handler: >-
curl -s https://mockapi.io/users
| jq -r '"# Users\n",
(.[] | "## \(.name)\nID: \(.id)\n")'
- name: how_to.md
type: readonly
|
MCP — server.py (18 lines)
import httpx
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("users")
@mcp.tool()
def list_users() -> str:
"""Fetches all users."""
response = httpx.get(
"https://jsonplaceholder.typicode.com/users"
)
response.raise_for_status()
users = response.json()
lines = ["# Users", ""]
for u in users:
lines.append(f"## {u['name']}")
lines.append(f"ID: {u['id']}")
lines.append("")
return "\n".join(lines)
if __name__ == "__main__":
mcp.run()
|
Add pipe: [stage1, stage2, stage3] to chain endpoints — stdout of each
stage becomes stdin of the next, in a single LLM write. A 5-step chain is
one model turn, not five. Per-stage schema validation runs before each handler.
Any stage error stops the pipeline immediately.
Edit folder.yaml or a handler script — changes take effect in ~1 second.
No restart. No reconnect. The watcher picks it up automatically.
A hung tool receives SIGTERM at the configured timeout (default: 30s), then SIGKILL after a 1-second grace period if it doesn't exit. The endpoint returns an error string. The filesystem never freezes.
Two shell pipelines on the same endpoint no longer clobber each other's results.
Invocation buffers are scoped by (inode, session-id) — echo
and cat from the same shell share a sid, so results are always routed to
the right caller. Handlers are dispatched asynchronously off the FUSE thread, so parallel
pipelines actually run in parallel. Abandoned slots are reaped after a 15-minute idle TTL.
Declare required env vars in folder.yaml. Users are prompted
at install time. Secrets are stored in secrets.env and loaded on every mount.
Built-in diagnostic command. Checks FUSE installation, your config file,
and every installed tool's folder.yaml. Prints actionable fixes.
Declare constraints on any endpoint: min_length, max_length,
pattern for strings; a schema: block with required fields and
property types for JSON. Invalid input is rejected before the handler runs.
Auto-documented in how_to.md.
All failures return [ERROR:CODE] message (5 parseable codes).
Each endpoint also exposes a companion <endpoint>.log file recording
duration_ms and stderr from the last run —
readable with cat forecast.log.
Declare state_file: /path/to/state.db in folder.yaml.
The runtime holds an exclusive POSIX lock (flock) for the duration of each
call and injects LIVEFOLDERS_STATE_FILE — no handler-side locking needed.
A virtual anthropic_tools.json is synthesized at read time from folder.yaml,
exposing each endpoint as an Anthropic-format tool definition. Hidden endpoints are excluded automatically.
Inject into tools=[] directly — 6–10% fewer tokens than MCP across an 8-task benchmark.
A virtual schema.json mirrors MCP's list_tools format:
tool names, descriptions, endpoint kinds, and full input constraints —
machine-readable by any MCP-aware client or script, alongside the human-readable
how_to.md.
Every handler runs in an OS-enforced sandbox. On Linux, Landlock LSM + seccomp
restricts filesystem paths and blocks outbound sockets. On macOS, sandbox-exec
applies equivalent SBPL rules. Network is denied by default — add network: true
in folder.yaml for tools that need it. Set mode: strict in
livefolders.yaml to refuse to mount if isolation cannot be applied.