Skip to content

Troubleshooting

The messages below are quoted as the server writes them; parts in angle brackets (<action>) vary. Most of them reach the model as a tool result with isError set, so the assistant can read the reason and often correct its own call. HTTP refusals and startup errors happen before any tool runs. Problems with a particular client’s configuration (where its log is, the Docker form of an entry, which surface to pick) are in Client setup.

A call that Arcane refused looks like this:

container.get failed: arcane: GET /environments/0/containers/web: 404 Not Found: Container not found
Hint: the referenced resource does not exist; use container.list to find valid IDs.
  • container.get is the action, GET /environments/0/containers/web the request it sent (under Arcane’s /api), and 404 Not Found: Container not found Arcane’s status and its own explanation.
  • The Hint line is the server’s suggestion for the next step, chosen from the status and from what Arcane wrote (below).

An error without a status (dial tcp …: connect: connection refused, tls: failed to verify certificate, context deadline exceeded) means the request never got an answer from Arcane.

Configuration errors are written to standard error and the process exits with status 2. Values that cannot be read are listed together:

config: ARCANE_MCP_READ_ONLY="ture" is not on or off (use true/false, 1/0, yes/no or on/off)
ARCANE_MCP_TIMEOUT="60" is not a duration (use a unit: 90s, 5m, 1h30m)

and, once every value reads, every missing setting and every combination that cannot work:

config: ARCANE_URL is required
ARCANE_API_KEY, or ARCANE_USERNAME and ARCANE_PASSWORD, are required in stdio mode
  • A desktop client usually reports only that the server “failed to start” or “disconnected”. The real message is in the client’s MCP log, or run the same command with the same variables in a terminal.
  • arcane-mcp --help lists every setting and its default, and exits with status 0 whatever the environment holds.
  • A combination is refused with a message naming both settings: for example ARCANE_MCP_HTTP_TOKEN cannot be used with ARCANE_MCP_HTTP_AUTH=apikey: …, ARCANE_URL lists several instances and a stdio server serves one: set ARCANE_MCP_INSTANCE to its name, or ARCANE_MCP_HTTP_TLS_CERT and ARCANE_MCP_HTTP_TLS_KEY must be set together. A certificate and key that do not load (missing, unreadable, not a pair) are a configuration error too.
  • A listener that cannot be opened (the port is in use, the socket path is taken) is found after the configuration: the server logs arcane-mcp stopped with the reason and exits with status 1. See Unix socket.
  • Apart from reading Arcane’s version in the background (see Arcane’s version differs from the catalog’s), which never stops or delays it, the server does not contact Arcane at startup. An unreachable Arcane or a wrong key shows up on the first call, not here.

Some problems are only warnings, logged at startup while the server goes on: an ARCANE_MCP_EXCLUDE_TOOLS entry that matches nothing, a deprecated LOG_LEVEL, an HTTP listener without a token (HTTP without ARCANE_MCP_HTTP_TOKEN: anyone who reaches the address can use the server, so keep it on a trusted network, which on TCP beyond loopback without ARCANE_MCP_HTTP_ALLOWED_HOSTS adds the DNS-rebinding risk), a TCP listener other machines can reach that serves plain HTTP, in any authentication mode (the HTTP listener serves plain HTTP on an address other machines can reach, …, unless ARCANE_MCP_HTTP_ALLOW_PLAINTEXT is set: true logs it at INFO, false refuses to start), and, on stdio, HTTP-only settings that stdio ignores (stdio mode ignores HTTP-only settings, …, naming them).

container.list failed: arcane: GET /environments/0/containers: Get "http://127.0.0.1:3552/api/environments/0/containers": dial tcp 127.0.0.1:3552: connect: connection refused

ARCANE_URL is wrong or not reachable from where the server runs.

  • In a container, localhost is the container itself: use the Arcane service’s name on a shared network, the host’s name, or host.docker.internal (Docker Desktop).
  • The server honours HTTPS_PROXY, HTTP_PROXY and NO_PROXY. If those are set for other tools, put Arcane’s host in NO_PROXY, or the requests go to the proxy.
  • Over HTTP, /readyz answers not ready: arcane is unreachable in the same situation, and the server logs readiness: Arcane health check failed with the cause.
  • A redirect to another host is refused (arcane: refused a redirect to another host: …): ARCANE_URL points at something that sends the request elsewhere, such as an http:// address that redirects to https://, or a login page in front of Arcane. Use the address Arcane answers on directly.
container.list failed: arcane: GET /environments/0/containers: Get "https://arcane.lan/api/environments/0/containers": tls: failed to verify certificate: x509: certificate signed by unknown authority

Arcane’s certificate is not signed by an authority the server trusts (a private CA or a self-signed certificate). The other common endings are x509: certificate is valid for …, not … (the name in ARCANE_URL is not in the certificate) and x509: certificate relies on legacy Common Name field, use SANs instead (the certificate has no subject alternative names).

  • Trust the authority. On Linux and in the container image, point SSL_CERT_FILE at a PEM file with your CA’s certificate (mount it into the container). On macOS and Windows, add the CA to the system’s trust store.
  • Fix the name. Use the host name the certificate was issued for in ARCANE_URL.
  • Last resort: ARCANE_SKIP_TLS_VERIFY=true turns verification off, for every instance. Anyone on the network path can then read the API key; use it only on a network you trust.

Arcane answers 404, 500, 502 or 503 when it cannot reach the Docker daemon of an environment or the agent of a remote one. The server recognises Arcane’s wording and says so instead of calling the resource missing:

container.get failed: arcane: GET /environments/0/containers/web: 404 Not Found: Failed to retrieve container: failed to connect to Docker: Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?
Hint: Arcane could not reach the Docker daemon of this environment, so this error does not mean the resource is missing. Check the environment with `environment.test` (it probes the connection) and `environment.get` (its status), and retry once it is reachable.

For a remote or edge environment the hint begins Arcane could not reach this environment's agent (a remote or edge environment that is offline or not connected). The actions it suggests are spelled for the surface in use (on meta, arcane_environment with the action test).

  • Local environment: Arcane has lost its Docker socket (the mount /var/run/docker.sock in Arcane’s container, its permissions, or Docker itself is down).
  • Remote or edge environment: the agent is stopped, cannot reach Arcane, or was paired with another key. environment.get shows its status.
  • environment.test counts as a change in Arcane’s API (it is a POST), so read-only mode withholds it and the hint names only environment.get; in safe mode it returns a preview.

A 401 inside a tool result is Arcane’s answer; a 401 to the HTTP request itself, before any tool runs, is the server’s own gate (see HTTP refusals). The hint names the credential the request actually carried:

HintCredential to check
Hint: Arcane rejected the credentials. Check ARCANE_API_KEY (or ARCANE_USERNAME/ARCANE_PASSWORD).The operator’s: stdio, or an HTTP client that sent no key of its own (or the server’s own key) in token mode
Hint: Arcane rejected the API key this client sent in its X-Arcane-API-Key header (the server's ARCANE_API_KEY is not used for it). …The key in the client’s X-Arcane-API-Key header, in token mode
Hint: Arcane rejected the API key this client sent as its Authorization Bearer token (the server's ARCANE_API_KEY is not used for it). …The client’s Bearer, in apikey mode
Hint: Arcane refused the apiKey parameter (missing or not valid), which is this action's only credential …The environment key passed to environment.pair or notification.dispatch, which never send the server’s credentials
Hint: this action does not send the server's credentials (ARCANE_API_KEY is not used); Arcane rejected the credentials passed in its parameters …What a public route such as auth.login was given in its parameters

The key may be mistyped, revoked, expired, or from another Arcane instance. In apikey mode a key that gets 401 from Arcane is also forgotten at once, so its next request is checked again and refused at the gate.

api_key.my_create failed: arcane: this operation accepts only a logged-in session; configure ARCANE_USERNAME and ARCANE_PASSWORD

A few account operations (passkeys, multi-factor authentication, your own API keys) are accepted by Arcane only from a logged-in session; log streams and other WebSocket actions say the same with needs a logged-in session when they need one. Configure a username and password as well as the key; the session is used only for those operations.

Over HTTP the login goes only to clients that run as the operator: a client that sends no key, or the server’s own ARCANE_API_KEY, in token mode. A client with its own key gets this error even when the server has a login configured, and in apikey mode, or with several instances, every client does. That is by design: the operator’s account is never lent to someone else’s key.

arcane: session login did not complete (mfa_required); an account that requires a second factor cannot be used by this server — use an API key

The configured account has multi-factor authentication. Use an API key instead.

container.list failed: arcane: GET /environments/0/containers: 403 Forbidden: …
Hint: the credential lacks the permission this action needs; an Arcane administrator can grant it through role assignments (role.user_assignments_set).

The key works, but its user’s roles do not allow this action on this environment. Either it is expected (you gave the assistant a narrow role on purpose) or an administrator grants the permission. The tool reference’s usage notes name the permission many actions need.

container.get failed: arcane: GET /environments/0/containers/web: 404 Not Found: Container not found
Hint: the referenced resource does not exist; use container.list to find valid IDs.
  • The hint names the domain’s list action. Many Arcane resources are found by ID only, not by name (projects, users, registries, API keys…), so the assistant must list them first.
  • 404 Not Found: Environment not found means the environmentId (or ARCANE_ENVIRONMENT_ID) does not exist on this Arcane. environment.list gives the IDs; 0 is Arcane’s local Docker.
  • A 404 whose explanation says Docker or the agent could not be reached gets the hint of Arcane cannot reach Docker or the agent instead: the resource may well exist.

Other statuses (400, 409, 422, 500) carry Arcane’s own explanation. For 400 and 422 the server adds the parameters the action accepts and requires, and, when Arcane names the fields it rejected, one line per field with the argument as you passed it, Arcane’s reason and the rejected value (never the value of a credential or of a file’s contents):

volume.create failed: arcane: POST /environments/0/volumes: 422 Unprocessable Entity: validation failed; body.driver: unknown driver
Fields Arcane rejected:
- driver (body.driver): unknown driver (got "nfs")
Required: name. Accepted: driver, driverOpts, environmentId, labels, name.

Arcane’s version differs from the catalog’s

Section titled “Arcane’s version differs from the catalog’s”
level=WARN msg="Arcane version differs from the catalog's major.minor: actions whose routes changed between the two may fail with 404 or 422; use an arcane-mcp release built for this Arcane version" instance=home arcaneVersion=v2.18.0 catalogVersion=v2.17.0

The catalog is generated from one Arcane release, the catalogVersion. At startup, over stdio and HTTP alike, the server asks each Arcane instance for its version (GET /api/version, a public route, sent without a credential) in the background, so the MCP handshake and the listener never wait for it. When the instance’s major.minor differs from the catalog’s, the server logs this warning, once per instance (again only if the instance later reports another version). A matching version is logged as Arcane version matches the catalog, and a development build (next, a commit) as a version that names no release.

  • The difference is a warning and nothing more: over HTTP /readyz stays ready, and every action runs except one that the instance’s release is known not to have (see An action needs a newer Arcane). Most routes do not move between minor releases, and a 503 would take a working server out of a load balancer for a version bump.
  • Under that warning, a 404 or 422 may come from a route or a field that changed between the two releases rather than from the call’s arguments. Use the arcane-mcp release that targets your Arcane version (the changelog names it), or run the Arcane release the catalog targets.
  • Over HTTP, /readyz?format=json shows catalogVersion and versionMatch, never the exact version, which only the log has (per instance with several; see Health, readiness and shutdown). When asked, the version is read again after 10 minutes, so an upgraded Arcane shows without a restart.
  • A version that cannot be read (Arcane down at startup, a proxy that blocks the route) stays unknown: versionMatch is null, the failure is logged only at ARCANE_MCP_LOG_LEVEL=debug, and the server works as before.
  • On stdio the version is read once at startup, and again, when it is older than 10 minutes, before a call to an action newer than the oldest release the catalog’s history covers. A session that ends within milliseconds of starting stops the startup read, so it may not log the warning at all.
action "podman.status" is not available: podman.status exists since Arcane v2.17.0; instance "prod" runs v2.16.1. Nothing was sent to Arcane; upgrade Arcane to use it.

The catalog records the first Arcane release that served each action (from the stock images v2.10.0 onwards). An action that appeared after v2.10.0 carries that release: find results and arcane://tools/{id} show it as since, and the tool reference as Since. Before calling such an action, the server compares it with the version it read from the instance (the same read as the warning above). On a release known to be older, the call is refused before anything is sent to Arcane and before a destructive call is put to you for confirmation, in the same words on every surface; the audit log records reason=older_arcane. Upgrade Arcane, or call another instance.

  • Before refusing, the server reads the version again if the one it holds is more than 30 seconds old, so after an upgrade a call is refused for at most about 30 seconds more; restarting the server clears it at once. Other version reads are kept for 10 minutes (the warning above, /readyz).

  • An unknown version is never a refusal: a version that could not be read, a development build (next, a commit) or a prerelease. The call goes to Arcane, and if Arcane answers 404 or 405 the error ends with the same sentence as a hint: Hint: podman.status exists since Arcane v2.17.0; this Arcane runs next, which names no release. If it is older, the route does not exist there.

  • Actions present in v2.10.0 are never checked, whatever the instance runs; the history starts there.

  • Only whether an action exists is checked. A parameter or field newer than the instance still reaches Arcane, which answers with its own error.

  • Each instance is judged by its own version, so with several instances a call can be refused on one and run on another.

Without confirm: true, on a client without elicitation, with ARCANE_MCP_ELICITATION=off, or in safe mode:

volume.delete is destructive (Remove a volume). Nothing was done. Repeat the call with confirm: true once the user has approved it.

The model is expected to ask you and repeat the call with confirm: true. On a client with elicitation, the same refusal comes with a note when asking failed: The user was asked to confirm it but did not answer within 5m0s. (ARCANE_MCP_ELICITATION_TIMEOUT) or Asking the user to confirm it failed, so it was not run.

When you answered the question:

The user declined to run volume.delete (Remove a volume) when asked to confirm it. Nothing was done. Do not retry it unless the user asks again.
The user dismissed the confirmation of volume.delete (Remove a volume) without answering. Nothing was done; ask the user before trying again.

These are not errors: nothing ran because you said no. See Confirmation of destructive actions.

An action that read-only mode or an exclusion withholds is answered with the reason on the dynamic and meta surfaces, whatever name the call used for it:

action "image.prune" is not available: the server runs in read-only mode (ARCANE_MCP_READ_ONLY)
action "image.prune" is not available: excluded by the server configuration (ARCANE_MCP_EXCLUDE_TOOLS)
  • On individual, a withheld action has no tool, so the client gets an unknown-tool error and the server writes no audit record.
  • The audit record of a withheld call carries reason=read_only or reason=excluded and the action, so the log tells you which setting removed it.
  • A name that matches no action gets suggestions: unknown action "volumes.prune". Did you mean: volume.prune, image.prune, …? Use arcane_find_action to search. On meta, unknown volume action "prunex". Valid actions: …, listing what the server serves in that domain.

If an action you expect is missing, check ARCANE_MCP_READ_ONLY and ARCANE_MCP_EXCLUDE_TOOLS where the server runs. Some calls that read as checks change something in Arcane and disappear in read-only mode: image_update.check_ref and updater.project_check store results, and environment.test is a POST.

A change “succeeded” but nothing happened

Section titled “A change “succeeded” but nothing happened”

In safe mode, a call that would change something answers with a preview and sends nothing:

## Restart container (container.restart)
- **action**: container.restart
- **executed**: false
- **note**: Safe mode is on (ARCANE_MCP_SAFE_MODE or --safe-mode): this mutating action was not sent to Arcane.
- **params**:
- **containerId**: web
- **request**: POST /api/environments/0/containers/web/restart
- **safeMode**: true

executed: false is the tell, and the audit record says outcome=previewed. Turn safe mode off when you want changes to happen: restart the server with ARCANE_MCP_SAFE_MODE unset or false and without --safe-mode, whichever of the two turned it on (a flag wins over the variable).

image.pull did not finish within the action deadline (30m0s, ARCANE_MCP_ACTION_TIMEOUT); it was cancelled. Arcane may still complete work it had already started: check its state before retrying. Cause: …

Large pulls, builds or deployments can run longer than ARCANE_MCP_ACTION_TIMEOUT; raise it. A single ordinary request is bounded by ARCANE_MCP_TIMEOUT (60s) instead, fails with context deadline exceeded, and is logged with reason=request_timeout. A reverse proxy in front of an HTTP server may have a shorter timeout of its own: nginx cuts a response that sends nothing for 60 seconds unless proxy_read_timeout is raised (see Behind a reverse proxy).

An image pull or a project deployment through a direct agent that stops after its first lines with unexpected EOF, while the manager logs Proxied response ended early, is a bug of Arcane v2.17.0 and v2.17.1’s environment proxy on reused connections. arcane-mcp no longer works around it: upgrade Arcane to v2.17.2, which fixes it (getarcaneapp/arcane#4592). Those releases share the catalog’s major.minor, so no version warning points at them.

Over Streamable HTTP, the transport refuses some requests before any tool runs. Every refusal is a JSON-RPC error whose code is the HTTP status times −100 (401 → -40100), with "id": null when it was made before the body was read:

{"jsonrpc":"2.0","id":null,"error":{"code":-40100,"message":"unauthorized: send the server's token as Authorization: Bearer <ARCANE_MCP_HTTP_TOKEN>"}}
StatusMessage (beginning)Cause and fix
401unauthorized: send the server's token as Authorization: Bearer <ARCANE_MCP_HTTP_TOKEN>Token mode: the Authorization header is missing or the token is wrong
401unauthorized: send your Arcane API key as Authorization: Bearer <key> (this server runs ARCANE_MCP_HTTP_AUTH=apikey)apikey mode: no Bearer token
401unauthorized: Arcane does not accept this API keyapikey mode: Arcane refused the key (or it is an environment access token, which is no user’s key)
400two different credentials: this server (ARCANE_MCP_HTTP_AUTH=apikey) takes the Arcane API key from Authorization: Bearer; drop X-Arcane-API-Keyapikey mode with a different key in X-Arcane-API-Key; drop the header
400no Arcane credential: send your Arcane API key in the X-Arcane-API-Key headerToken mode with no operator credentials for this instance and no key from the client
400this server serves several Arcane instances: name one in the X-Arcane-URL header (its name, or its URL as configured)Several instances and no X-Arcane-URL; send one X-Arcane-URL header when it was repeated
400Accept must contain both 'application/json' and 'text/event-stream'A hand-made request (curl) without the headers Streamable HTTP requires
403X-Arcane-URL names an Arcane instance this server does not serveThe instance is not in ARCANE_URL; names are case-sensitive. In apikey mode it also counts as a failed authentication
403request refused: the Host is not allowed by this server (see ARCANE_MCP_HTTP_ALLOWED_HOSTS)The Host the client (or the proxy) sends is not in the list; add it, or make the proxy pass the client’s Host
403Forbidden: invalid Host header "<host>"A loopback listener without ARCANE_MCP_HTTP_ALLOWED_HOSTS reached with a non-loopback name (a proxy forwarding the public name, or a container name); set the list
403cross-origin request refused: the Origin is not trusted by this server (see ARCANE_MCP_HTTP_TRUSTED_ORIGINS)A browser-based client on another origin; add its origin to the list
403this session was opened with another Arcane API key: …The client changed keys (or instance) mid-session; send the same one, or initialize a new session
404session not found (plain text)The session expired (ARCANE_MCP_HTTP_SESSION_IDLE_TIMEOUT), the server restarted, or a load balancer sent the request to another replica; clients initialize again on their own
405method not allowed: this server runs stateless Streamable HTTP …Stateless mode serves only POST; the client tried to open an event stream or delete a session
400Invalid Request: a message nests JSON deeper than 100 levelsA message in the body nests objects and arrays past 100 levels (JSON-RPC code -40000); no client this server knows sends one, so look for a value built by mistake, such as a structure that contains itself
413request body exceeds 16777216 bytesA body over ARCANE_MCP_HTTP_MAX_BODY_BYTES. A proxy may refuse smaller bodies first (nginx: client_max_body_size)
429too many failed authentications from this address or its IPv6 /48 (ARCANE_MCP_HTTP_AUTH_MAX_FAILURES); retry after the time in Retry-AfterToo many wrong tokens or keys from one address, or ARCANE_MCP_HTTP_AUTH_NETWORK_FACTOR (10) times that many refused credentials across the /64s of one IPv6 /48 (0 turns that limit off). Behind a proxy, every client shares the proxy’s address unless ARCANE_MCP_HTTP_TRUSTED_PROXIES is set
429rate limit: too many requests with this Arcane API key (ARCANE_MCP_HTTP_RATE_LIMIT_RPS); …The key’s rate limit; wait for Retry-After
429Too many requests for the server card from this address (ARCANE_MCP_HTTP_DISCOVERY_RATE_LIMIT_RPS). Retry later.One address asked for /server-card or /mcp/server-card faster than its bucket allows; wait for Retry-After, or cache the card (it has an ETag)
503too many requests in flight …, too many sessions are open …, too many Arcane API keys are in use at once …A cap is full (ARCANE_MCP_HTTP_MAX_CONCURRENT_REQUESTS, _MAX_SESSIONS, _MAX_API_KEYS); retry after Retry-After or raise the cap
503could not check the API key with Arcane; retry laterapikey mode: Arcane did not answer the key check clearly (unreachable, or something in front of it answered); too many API keys are being checked at once; retry later when 16 checks are already running

Refusals are logged at warn (HTTP request refused: Host not allowed, … cross-origin, … an Arcane instance this server does not serve, … could not check the API key with Arcane) and failed authentications at info with the client address (HTTP request refused: failed authentication addr=… reason=…), so the server’s log tells you which guard answered and whom it charged. If every failure shows the proxy’s address, set ARCANE_MCP_HTTP_TRUSTED_PROXIES.

  • Clients cannot connect, and the log shows TLS handshake failed. The error field says why: client sent an HTTP request to an HTTPS server means the client uses http://; errors such as remote error: tls: bad certificate or local error: tls: bad record MAC usually mean the client does not trust the certificate (a self-signed one, or a chain without its intermediate). These warnings are throttled to one a minute with suppressed=<n> counting the ones left out, plus a TLS handshakes failed and were not logged line at the end of a burst; set ARCANE_MCP_LOG_LEVEL=debug to see each one.
  • A renewed certificate is not served. The server picks up new files at the next handshake (checked at most once a second) and logs reloaded the TLS certificate. the TLS certificate on disk cannot be loaded; serving the previous one means the new pair does not load yet (half written, key and certificate from different renewals); it is logged once per state of the files. In a container, mount the directory rather than the two files, or the container keeps seeing the old ones.
  • serve HTTP: "<path>" exists and is not a socket; refusing to replace it: a regular file or directory is at ARCANE_MCP_HTTP_ADDR. Choose another path or remove it.
  • serve HTTP: unix socket "<path>" is already served by another process: another arcane-mcp (or something else) answers on it. A socket left by a crashed run, which nobody answers on, is replaced with a warning (removed a stale unix socket left by an earlier run).
  • The proxy gets permission denied (nginx: connect() to unix:… failed (13: Permission denied)). The socket has ARCANE_MCP_HTTP_SOCKET_MODE (0660) and belongs to the server’s user and group: run the server with a group the proxy is in, and make sure the proxy can enter the socket’s directory.
  • Every client shares one auth-failure budget. A socket connection has no client address, so failures are charged to unix unless ARCANE_MCP_HTTP_TRUSTED_PROXIES contains unix and the proxy fills ARCANE_MCP_HTTP_TRUSTED_PROXY_HEADER.

arcane-mcp --probe (the image’s HEALTHCHECK) prints what it found and exits 0 healthy, 1 unhealthy, 2 on a usage error:

  • arcane-mcp --probe: unhealthy: …: nothing answered at the configured address within 3 seconds (--timeout), or it answered with another status. The probe reads ARCANE_MCP_HTTP_ADDR and ARCANE_MCP_HTTP_TLS_CERT from the same environment and .env as the server; if you changed them with flags on the server’s command line, pass the same flags after --probe.
  • the server listens on port 0, chosen by the kernel: …: pass the port the server logged, as --http 127.0.0.1:<port>.
  • arcane-mcp --probe: stdio mode (ARCANE_MCP_HTTP_ADDR is not set): …: a stdio container has no listener and probes healthy while it runs.
  • /readyz (--probe --ready) failing while /healthz succeeds means the server is up but cannot reach Arcane, or is draining; liveness stays healthy so the container is not restarted for Arcane’s sake. An Arcane version that differs from the catalog’s never makes /readyz fail: see Arcane’s version differs from the catalog’s.
  • A malformed line does not end the session. It is answered with a JSON-RPC error (-32700 Parse error, or -32600 Invalid Request: …, for example for a line over 16 MiB) and the next line is read as usual.
  • Closing stdin does not lose answers. The server answers every request already sent before it exits with status 0, so printf '…' | arcane-mcp gets the answer of a running tool call too. The wait is bounded by ARCANE_MCP_ACTION_TIMEOUT; a destructive call waiting for an elicitation answer the departed client can no longer give ends after ARCANE_MCP_ELICITATION_TIMEOUT with the confirm: true refusal. A signal still ends the process within 2 seconds.
  • Standard output is the protocol. Nothing else may write to it; a wrapper script that prints to stdout breaks the session. The server’s own logs go to stderr.
  • The Docker form hangs or exits at once. See Client setup: keep -i, never add -t or -d.
  • Where: standard error only. For a stdio server that is the client’s MCP log (not the chat); for a container, docker logs.
  • How much: ARCANE_MCP_LOG_LEVEL (or --log-level): debug, info (default), warn or error. debug adds detail such as failed completion lookups, each failed TLS handshake and HTTP servers reclaimed from the pool.
  • The audit log: one msg="tool call" record per call at info (ARCANE_MCP_AUDIT_LOG), with the outcome and reason, which shows whether a call was refused (reason=needs_confirmation, unknown_action, invalid_args, read_only, excluded), declined, previewed or failed (status=404, reason=action_deadline). A level above info hides it. See Logs and audit trail.
level=INFO msg="tool call" surface=dynamic tool=arcane_execute_action action=volume.delete outcome=refused reason=needs_confirmation duration=246µs
level=INFO msg="tool call" surface=dynamic tool=arcane_execute_action action=image.prune outcome=refused reason=excluded duration=26µs
level=INFO msg="tool call" surface=dynamic tool=arcane_execute_action action=container.list outcome=error duration=524ms status=404

When reporting a problem, include arcane-mcp --version, the Arcane version, the transport, the client, the error text and the matching log lines (they contain no argument values or keys).