Quickstart
On this page
Five steps take an installed Hub to its first answered script: create the configuration and the token, enable Inkscape, declare the Hub in your MCP client, check what the Hub sees, send a script. It is for engineers who already have the package; Inkscape needs no bridge. Otherwise start with Installation.
Create the configuration and the token
Run this once, as your own user:
libremodular-mcp init
It prints one line per directory and per file it creates; this page writes $HOME for the start of each path:
directory ready: $HOME/.config/libremodular-mcp
directory ready: $HOME/.local/state/libremodular-mcp
configuration created: $HOME/.config/libremodular-mcp/config.toml
token created: $HOME/.config/libremodular-mcp/token
Both files are in mode 600. Run a second time, init leaves them as they are and says configuration exists, unchanged and token exists, unchanged.
Enable Inkscape
After init, every application is disabled. This command enables Inkscape:
sed -i '/^\[apps.inkscape\]/,/^$/ s/enabled = false/enabled = true/' ~/.config/libremodular-mcp/config.toml
The entry in config.toml then reads:
[apps.inkscape]
enabled = true
mode = "cli"
Inkscape 1.4 is the version this page ran against. In the cli mode the Hub starts one Python process per script, so there is no bridge to start. GIMP, Krita, Blender and LibreOffice are reached through a bridge that you start by hand; each guide gives the commands: GIMP, Krita, Blender and LibreOffice.
Declare the Hub in your MCP client
The client runs the Hub as a command with the argument serve. With the package, the command is /usr/bin/libremodular-mcp; built from the sources, it is the absolute path of target/release/libremodular-mcp in your clone.
{
"mcpServers": {
"libremodular": {
"command": "/usr/bin/libremodular-mcp",
"args": ["serve"]
}
}
}
The Hub needs the variable XDG_RUNTIME_DIR, which a desktop session sets. Without it, libremodular-mcp serve stops at once with error: XDG_RUNTIME_DIR is not set; refusing to write volatile files elsewhere.
Connect your model gives this entry for Claude Code and for opencode, each tried in the client, with the answer to get_state that the client received.
Make the first call
The guide for the model makes get_state on hub the first call: it lists the applications the Hub can reach. Ask your model to make it, or run the client of the Demonstration, whose first answer is this one:
{
"app": "hub",
"app_version": "0.1.0",
"bridge_version": null,
"captured_at": "2026-10-21T07:57:39.858Z",
"connected": true,
"content_origin": "hub",
"screenshot": null,
"state": {
"modules": [
{
"app_version": "1.4",
"bridge_version": null,
"connected": true,
"mode": "cli",
"name": "inkscape"
}
]
},
"warnings": []
}inkscape is connected, in the cli mode, and its app_version is 1.4. The Hub exposes two tools and no more: a client that asks for the list of tools gets ["execute_script", "get_state"].
Send the first script
A model sends a script like this one through execute_script. To send it yourself, save it as first.py, save the client of the Demonstration as client.py, and run python3 client.py first.py.
import json
print("the script ran inside Inkscape's Python")
print("LMM_RESULT: " + json.dumps({"answer": 6 * 7}))The third answer of the client is the Hub’s answer to the script:
{
"app": "inkscape",
"duration_ms": 30,
"error": null,
"result": {
"answer": 42
},
"status": "ok",
"stderr": "",
"stdout": "the script ran inside Inkscape's Python\n",
"truncated": false
}stdout is what the script printed, result is the value after LMM_RESULT: , and status is ok. The guide for the model lists the other statuses (error, refused, timeout, busy and unavailable) and what to do with each: guide for the model. A script that draws, and the image it produced, are on the Demonstration page.