Configuration¶
Everything is optional. Environment variables use the prefix SNAIL_MCP_BLENDER_, with __ between a
section and a field.
| Variable | Default | Meaning |
|---|---|---|
SNAIL_MCP_BLENDER_DATA_DIRECTORY |
~/.s3l-mcp-blender |
This server's own files: the add-on zip, downloads when there is no project and, when Blender runs here, the token. The add-on reads the same variable for its journal, leases, render jobs, batches and snapshots, which live on the machine Blender runs on |
SNAIL_MCP_BLENDER_PROJECT_DIRECTORY |
the folder the client starts the server in | Over stdio, the project on this machine: blender_download brings files into it, relative blender_upload paths are read from it, and its twin on Blender's machine is the add-on's files/<its name>. The home folder and the root count as no project. A server over HTTP sees none of the client's folders and ignores it; blender_open_project names the project there |
SNAIL_MCP_BLENDER_TRANSPORT |
Stdio |
Stdio when the client starts the server; Http when it runs on its own beside Blender, in a container, and clients connect to it — Blender in Docker |
SNAIL_MCP_BLENDER_HTTP__URL |
http://127.0.0.1:8080 |
Over HTTP: the address to listen on; the image sets http://0.0.0.0:8080 |
SNAIL_MCP_BLENDER_HTTP__TOKEN_FILE |
— | Over HTTP: the file holding the token clients present — as a bearer on /mcp and at the pages' sign-in. Required: without it, or HTTP__TOKEN, the server refuses to start |
SNAIL_MCP_BLENDER_HTTP__TOKEN |
— | The same token given directly, for a quick local run; it wins over HTTP__TOKEN_FILE. Either is read once at start, so a new token takes a restart |
SNAIL_MCP_BLENDER_HTTP__PUBLIC_URL |
HTTP__URL |
The address clients reach the server at behind a reverse proxy; the links blender_upload and blender_download hand out are built on it, and an https address marks the session cookie Secure |
SNAIL_MCP_BLENDER_HTTP__LINK_MINUTES |
15 |
How long those links work, 1 to 1440 |
SNAIL_MCP_BLENDER_BRIDGE__HOST |
127.0.0.1 |
Where the server finds the add-on: the loopback, or the Blender container's name when both run in containers. A Blender on another machine is reached through the tunnel, never directly |
SNAIL_MCP_BLENDER_BRIDGE__PORT |
9876 |
Must match the port in the add-on preferences |
SNAIL_MCP_BLENDER_BRIDGE__CONNECT_TIMEOUT_SECONDS |
5 |
Opening the socket |
SNAIL_MCP_BLENDER_BRIDGE__REQUEST_TIMEOUT_SECONDS |
30 |
One reply; renders, imports and Python pass their own |
SNAIL_MCP_BLENDER_IDLE_TIMEOUT_MINUTES |
0 |
Over stdio: exit after this long without a tool call; 0, the default, disables it, since a client that ends closes the pipe and the server exits with it. A server over HTTP never exits on its own |
SNAIL_MCP_BLENDER_SKILL_IDLE_MINUTES |
0 |
Unload a skill unused for this many minutes; 0 keeps skills loaded, which suits clients that cache the tool list |
SNAIL_MCP_BLENDER_BRIDGE__TOKEN |
— | Shared secret for the add-on; empty reads the one the add-on generated into <data>/state/token |
SNAIL_MCP_BLENDER_BRIDGE__TOKEN_FILE |
<data>/state/token |
Where to read that generated token when it lives outside this server's data directory |
SNAIL_MCP_BLENDER_BRIDGE__TUNNEL__HOST |
— | user@host of a Blender on another machine: the server opens an SSH tunnel to it at start, reopens it after a drop and closes it on exit; empty keeps the link on this machine |
SNAIL_MCP_BLENDER_BRIDGE__TUNNEL__KEY |
— | Private key for that login; the SSH agent and ~/.ssh/config decide when empty |
SNAIL_MCP_BLENDER_BRIDGE__TUNNEL__REMOTE_PORT |
9876 |
The add-on's port on the other machine; BRIDGE__PORT is the local end of the tunnel |
SNAIL_MCP_BLENDER_AGENT |
— | Name this server signs its requests with; the add-on's journal and leases tell agents apart |
SNAIL_MCP_BLENDER_BRIDGE__AGENT |
AGENT |
The name the link signs with, when it should differ from AGENT |
SNAIL_MCP_BLENDER_PYTHON |
allow |
Passed to Blender as well (--python in compose), so off holds even for a client that reaches the add-on another way. fallback runs only scripts whose work no tool covers, in run_tools and blender_batch steps as in blender_python; it reads the script as text, so it steers the agent towards the tools rather than guarding the door. off switches blender_python off together with the operators that run scripts or install code — the script, console, preferences and extensions modules, text.run_script, and anything asked to trust a file's own scripts — sequences and batches holding a python step, and uploads outside the add-on's files folder; the dedicated tools and the other operators stay |
SNAIL_MCP_BLENDER_OCIO_CONFIG |
— | OpenColorIO config background render jobs run under; the running Blender reads OCIO only at start-up |
SNAIL_MCP_BLENDER_CONFIG |
— | Path of the settings file, the only one read when it is set, and none when it does not exist; a leading ~/ is expanded |
Every range lives as an attribute on the setting it constrains, and the server checks them all while the host
starts: a port outside 1 to 65535, a timeout of zero or less, negative minutes, link minutes outside 1 to 1440. The
process then exits with OptionsValidationException naming each setting it refused and the range it allows; a server
over HTTP without a client token exits the same way, naming HTTP__TOKEN and HTTP__TOKEN_FILE. A value that is not a
number, or a PYTHON or TRANSPORT that is none of its names, stops the process with InvalidOperationException
instead. Nothing is repaired in
silence, so a typo in the environment is visible immediately instead of turning into a link that never connects.
Token¶
The add-on demands a token on every request. Left empty in its preferences, it generates one on first start
into <data directory>/state/token, readable by the user only, and the server reads that file whenever it
connects, so a fresh install needs nothing typed. Set the same value on both sides by hand when the server and
Blender use different data directories. For a Blender on another machine, copy the token it generated into a file
readable by you alone and point SNAIL_MCP_BLENDER_BRIDGE__TOKEN_FILE at it, so the MCP entry holds a path and no
secret; Blender on another machine shows the commands. A Blender without an interface takes its token from
blender -b -c snail_bridge --token-file <file> instead, and --host sets the address it listens on, the container
network in Docker; point SNAIL_MCP_BLENDER_BRIDGE__TOKEN_FILE at the same file.
Clients and their keys¶
A server reached over HTTP admits clients by key, one key each:
$ s3l-mcp-blender clients add lighting --scope read,write,farm
lighting — read, write, farm
l7m82DheQD9RO3z3RWjSgr0Gv87LgkjQfGvRwEDPhTk
This is the only time the key is shown; give it to the client and keep no copy here.
The client sends it as Authorization: Bearer <key>. clients list names the clients and what each may do, and
clients revoke <name> stops admitting one — at its next request, without restarting the server, and its browser
session with it. Only the digest of a key is kept, under <data directory>/state/clients.json, so a copy of that file
opens nothing and a key that is lost is reminted rather than looked up.
The name on the key is the agent name the client's commands are signed with, which the add-on's leases and journal record; the client cannot choose it (see Agents).
| Scope | Opens |
|---|---|
read |
Reading the scene, the files and the diagnostics |
write |
Changing the scene and writing files, uploading included |
delete |
Deleting objects and files, replacing a file that exists, clearing another agent's lease, undoing |
python |
blender_python and blender_run_operator, which reach past every schema |
farm |
Background renders and batches, which spend the machine after the call returns |
A key minted without --scope gets read, write, delete and farm: Python is asked for by name.
run_tools and run_program need no scope of their own: each command they carry is asked about by its own scope
before any of them is sent, so a key with read, write and farm runs a program that builds a scene and is refused
one that deletes from it. blender_batch needs farm, because it starts a second Blender, and then the same for every
step. blender_upload is write work, and delete only with overwrite, which replaces a file that is there — the
same over /raw with a key; a signed link was granted by the tool that issued it and needs no scope.
SNAIL_MCP_BLENDER_HTTP__TOKEN still works and opens everything, so a server set up before keys existed keeps
running and its clients move over one at a time. It is also the only key whose holder may still name itself with the
header X-Snail-Agent.
State the add-on keeps¶
The add-on writes what must outlive a Blender session under <data directory>/state: journal.jsonl
(every mutating command with its agent), leases.json (objects agents hold) and jobs.json (the render
queues to pick up after a restart). Worker Blenders started for batches and render jobs inherit the data
directory, so their commands land in the same journal and respect the same leases. The add-on reads
SNAIL_MCP_BLENDER_DATA_DIRECTORY from Blender's own environment; when Blender is started from a launcher
without it, the default ~/.s3l-mcp-blender applies, which is also the server's default — or ~/.snail-mcp-blender
while only a folder of that name, from before the rename, is there. Next to state/ it keeps
jobs/, batches/, snapshots/ and files/, all on the machine Blender runs on; the working
order maps them.
Settings file¶
The same keys as a JSON file, under a Snail section. The chain is Snail.Sdk's, the same for every Snail server. A file
named in SNAIL_MCP_BLENDER_CONFIG is the only one read, and when it does not exist no file is. Without that variable
only the first file that exists is read: .s3l-mcp-blender.json and s3l-mcp-blender.json in the working directory,
~/.config/s3l-mcp-blender/config.json, ~/.s3l-mcp-blender.json. The names from before the rename are not read.
{
"Snail": {
"Bridge": { "Port": 9876, "RequestTimeoutSeconds": 45, "Token": "the add-on's token" },
"IdleTimeoutMinutes": 0
}
}
Environment variables win over the file, setting by setting.
A setting of this machine — a token above all, Bridge.Token or Http.Token — belongs in
~/.config/s3l-mcp-blender/config.json, readable by you alone (chmod 600), never in a launchd job or in a client's
registration: those travel wherever the file is copied, and the settings file serves every client and a server over
HTTP alike.
Limits¶
| Timeout per call | 1 to 600 seconds, set per call by timeoutSeconds where a tool has it; a value outside that range is refused, not clamped |
| Render resolution | 4096 pixels per edge |
| Request size | 16 MB per JSON line to the add-on |
| Reply size | 4 MB from the add-on; larger replies come back as an error asking for less |
| Queued commands | 64 waiting for Blender's main thread; beyond that the add-on answers Busy |
| Sequence | 500 steps per run_tools; step results leave the reply once it passes half a megabyte, each marked omitted |
| Transfer chunk | 8 MB up, 2 MB down, the whole file checked by SHA-256 at the end |
| Upload part over HTTP | 16 MB per request of the command blender_upload returns, so a proxy that reads a body for a minute never cuts one off |
| Folder listing | 5,000 files per page; a download walks the pages, and past 20,000 files in all the folder is refused as TooManyFiles and comes down folder by folder. The HTTP archive still takes one listing |
| Folder on the pages | 2,000 entries per folder; the page says when it shows only the first 2,000 |
| Text preview | 256 KB on the pages; larger files are only downloaded |