Reload-Config
Tool Name: daemon/reload-config
Re-reads mcpd's config files - daemon.yaml, users.yaml and mcp-sudo.yaml - and applies them without restarting the daemon: users and tokens, per-user grants, rate limits and tool timeouts. It takes no arguments and returns what changed.
- It only reads the files. They are edited on the host - with
linuxctl create|update|delete mcpd userorlinuxctl edit mcpd config, which call this tool afterwards themselves. There is deliberately no MCP tool that writes them. - Validated first, strictly. If any file is invalid - including a key mcpd doesn't know, such as
path:forpaths:- nothing changes, the daemon keeps running on the config it has, and the error is returned. - Takes effect at once. A new user can connect right away; a removed user, or one whose token changed, can't - and their open sessions are closed. Cached tool and resource results are dropped, since they may have been produced under grants that no longer apply.
- Needs a restart:
server.port,server.tlsandworker.containerized. When they changed, the reply lists them under "Need a restart to take effect". - Only for users granted it in
mcp-sudo.yaml(daemon/reload-config: {allowed: true}); for everyone else it isn't intools/list.scripts/install.shgrants it to the first user. See mcp-sudo.yaml.
The daemon writes every reload as an audit line - at any log level - with the calling user and the changes, e.g. 2026-09-24T10:41:28.180Z INFO config reloaded audit=true user=privileged changes=2 detail="user testuser: added; grants testuser: + disks/usage (root; paths [/var])"; a rejected reload is a WARN config reload rejected, keeping the current config line. Token values and hashes never appear in the reply or the log.
Example
Every example below shows the equivalent linuxctl command and the raw MCP JSON-RPC call it resolves to. The raw call always follows the same two-step pattern (see MCP API overview for the full explanation): open an SSE stream to get a one-time POST endpoint, then POST the JSON-RPC request there - the result streams back on the SSE connection.
linuxctl
linuxctl reload daemon
Output, after adding testuser and granting it disks/usage:
Reloaded configs/daemon.yaml, configs/users.yaml and configs/mcp-sudo.yaml.
Changes:
user testuser: added
grants testuser: + disks/usage (root; paths [/var])
With nothing changed since the last load:
Reloaded configs/daemon.yaml, configs/users.yaml and configs/mcp-sudo.yaml.
No changes.
With an invalid file - the running config stays as it was:
config not reloaded, the current one stays in effect: configs/users.yaml: yaml: line 1: did not find expected node content
curl (raw MCP JSON-RPC)
# 1. Open the SSE stream (in the background) and capture the one-time POST endpoint
curl -N -s --cacert mcpd.crt -H "Authorization: Bearer $MCP_TOKEN" https://localhost:9091/sse &
# server sends: event: endpoint / data: /message?session_id=...
# 2. POST the tools/call request to that endpoint
curl -s --cacert mcpd.crt -X POST "https://localhost:9091/message?session_id=<from step 1>" \
-H "Authorization: Bearer $MCP_TOKEN" \
-H "Content-Type: application/json" \
-d '{"jsonrpc": "2.0", "id": "1", "method": "tools/call", "params": {"name": "daemon/reload-config", "arguments": {}}}'
# 3. The result arrives on the SSE stream opened in step 1
Response:
{
"jsonrpc": "2.0",
"id": "1",
"result": {
"content": [
{
"type": "text",
"text": "Reloaded configs/daemon.yaml, configs/users.yaml and configs/mcp-sudo.yaml.\nChanges:\n user testuser: added\n grants testuser: + disks/usage (root; paths [/var])\n"
}
]
}
}