MCP server
The Shardflux MCP server, hosted at mcp.shardflux.dev with OAuth or local as @shardflux/mcp. Client setup, configuration, every tool, wake and errors.
Overview
The Shardflux MCP server gives any MCP client or agent framework the tools of your Shardflux workspaces. It runs two ways, with the same tools:
- Hosted at
https://mcp.shardflux.dev/mcp: add the URL to your client and sign in. Nothing to install and no key to copy. See Hosted endpoint. - Local as
@shardflux/mcp, a stdio server your client starts withnpxand a project API key. See Client setup.
The rest of this page describes the local server. A feature marked with a version, such as (0.4.0+), is not in earlier releases.
- It runs on your machine with a project API key you supply, and translates each tool call into one
@shardflux/sdkrequest or wait. - It has no agent loop of its own and keeps no local workspace directory. Its only state is one workspace handle per key, so tool tokens are reused between calls.
- It needs Node.js 24 or later. Run it with
npx -y @shardflux/mcp; the package's binary isshardflux-mcp.
SHARDFLUX_API_KEY=sfk_... npx -y @shardflux/mcpThe server speaks MCP on stdin and stdout and logs to stderr. Your MCP client starts it; you do not run it by hand except to test it.
Hosted endpoint
https://mcp.shardflux.dev/mcp serves the Shardflux tools over MCP Streamable HTTP and signs your client in with
OAuth. Any MCP client that supports Streamable HTTP and OAuth connects with the URL alone:
- Add the URL to your client.
- The client opens Shardflux in your browser. Sign in, choose the project the client works in, and select Connect.
- You are back in the client, connected. The connection is a project API key named
<client> (MCP connector)with every tool permission, listed on the project's API keys page in the console. Revoke it there to disconnect the client.
The client renews its access on its own, so the connection lasts until you revoke it. A client that reads the standard
mcpServers JSON config takes the URL as its entry:
{
"mcpServers": {
"shardflux": {
"url": "https://mcp.shardflux.dev/mcp"
}
}
}Set the client's tool timeout above the server's 120-second per-call deadline, so the server's own timeout result
reaches the agent.
Hosted: API key header
A client configured with headers can send a project API key instead of signing in:
Authorization: Bearer sfk_...Hosted and local
The hosted endpoint is always on the current version. A few things are set differently:
template_buildtakes the recipe in the call (recipe). Building from atemplate.yamlon your machine (file) is done with the local server.- The environment settings of the local server (
SHARDFLUX_WORKSPACE_KEY,SHARDFLUX_TEMPLATEand the deadlines) are arguments of each call instead: passworkspace_keyandtemplatetoworkspace_open. Each call has a 120-second deadline; start long commands withexecandbackground: true.
Client setup
Your MCP client starts the local server with npx -y @shardflux/mcp and passes the configuration as environment
variables. Use a project API key whose tool permissions cover what the agent should do (see
Permissions). In a client that reads the standard mcpServers JSON config:
{
"mcpServers": {
"shardflux": {
"command": "npx",
"args": ["-y", "@shardflux/mcp"],
"env": {
"SHARDFLUX_API_KEY": "sfk_...",
"SHARDFLUX_TEMPLATE": "default"
}
}
}
}Add SHARDFLUX_WORKSPACE_KEY to give the agent one workspace (Pinning); every variable is in
Configuration.
Set the client's tool timeout above the server's per-call deadline (SHARDFLUX_MCP_TOOL_TIMEOUT_MS, 120 seconds by
default), or lower that deadline, so the server's own timeout result reaches the agent.
Configuration
The server reads its configuration from the environment when it starts. Invalid configuration exits with code 2 before serving, with one JSON line on stderr.
| Variable | Default | Meaning |
|---|---|---|
SHARDFLUX_API_KEY |
required | Project API key, sfk_<key id>_<secret>. Its tool permissions decide which workspace tools are listed. |
SHARDFLUX_API_URL |
https://api.shardflux.dev |
API origin. Must be https (plain http only for loopback hosts), without credentials, query or fragment. |
SHARDFLUX_WORKSPACE_KEY |
none | Pins one workspace (1-200 printable characters). See Pinning. |
SHARDFLUX_TEMPLATE |
none | Default template slug for workspace_open, for example default (the platform default template). With it, template becomes optional, and (0.9.0+) a workspace tool called with a key that has no workspace yet creates it from this template. |
SHARDFLUX_WORKSPACE_MODE |
none | (0.4.0+) processful or file_first: the mode workspace_open sends when the call names none (unset: the API's default, processful for a new key). A pinned server also lists the tools of this mode until its workspace exists. |
SHARDFLUX_MCP_TOOL_TIMEOUT_MS |
120000 |
Default and maximum deadline per tool call, 1000-3600000 ms. A call's timeout_ms can only shorten it. |
SHARDFLUX_WAKE |
on |
on: workspace tools resume a suspended workspace, then run. off: they return the workspace_not_running refusal. |
SHARDFLUX_WAKE_TIMEOUT_MS |
120000 |
Longest wait per call for a workspace to wake or finish a transition, 1000-3600000 ms. Clamped to SHARDFLUX_MCP_TOOL_TIMEOUT_MS; each wake also ends 250 ms before the call's deadline. |
SHARDFLUX_AGENT_LABEL |
mcp |
Attribution label of every tool token the server obtains (1-100 printable characters). It appears as an agent session in the console and in shard ws sessions. |
SHARDFLUX_MCP_LOG_LEVEL |
info |
debug, info, warn or error. |
SHARDFLUX_HTTP_KEEPALIVE |
unset | 0.6.0+: pooled HTTP/1.1 on Node 26 by default; 0 forces close for diagnosis, 1 opts into native pooling. |
SHARDFLUX_NO_UPDATE_CHECK |
unset | (0.4.0+) 1, true, yes or on turns off the startup update check (see Updates). |
NO_UPDATE_NOTIFIER |
unset | (0.4.0+) The npm convention: any non-empty value also turns the check off. |
Tools
Every tool takes an optional timeout_ms (1-3600000): the call's deadline, clamped to
SHARDFLUX_MCP_TOOL_TIMEOUT_MS. Every tool that works on a workspace takes workspace_key, required unless the server
is pinned. A workspace key is resolved by exact match within the API key's project, across every lifetime
and purpose, so sessions, template drafts and test instances resolve too; the live workspace wins over tombstones of
ended sessions with the same key.
Management tools
| Tool | Arguments (required in bold) | Does |
|---|---|---|
workspace_open |
workspace_key, template (optional with SHARDFLUX_TEMPLATE), cpu_millis, memory_mib, disk_gib, lifetime (persistent or session), inputs, mode (processful or file_first), wait (default true) |
Opens by key: creates the workspace on first use, reconnects to or resumes it afterwards, never resets it. Waits until it is ready, the template's start commands and services included, unless wait: false. inputs (0.3.0+) passes the template's text inputs, {"NAME": "value"}. mode (0.4.0+) opens a file-first workspace. (0.7.0+) memory_mib_held (at least 512) sets what the workspace holds while idle, and memory_mib the most it may use: elastic memory. allocation_mode is deprecated: accepted and ignored. (0.12.0+) like creates a fresh disk with the source's exact template and options; volumes sets the shared volumes: supplied volumes replace the set and omission preserves it. Returns {workspace, ready} and timing. |
workspace_list |
prefix, state, lifetime (persistent, session, any), purpose (standard, template_draft, template_test, any), include_deleted, limit (1-200, default 50), cursor |
The project's workspaces: {workspaces, next_cursor}. By default only persistent standard workspaces. |
workspace_status |
workspace_key |
One workspace plus its five most recent operations. |
workspace_suspend |
workspace_key, wait (default false), durable (0.6.0+, default false), after_seconds (0-3600, 0.4.1+; 0 = as soon as it is idle, 0.5.1+) |
Suspends the workspace. Returns the operation; with wait: true, once it has finished (sealed on its host). (0.6.0+) The result has durable and durability (durable storage); durable: true implies wait and returns once the checkpoint is in durable storage. With after_seconds (0.4.1+), suspend when idle instead: the workspace is suspended once it has been idle that long; the agent's next tool call on it cancels that, and a running command or a keepalive postpones it. Returns suspend_request (not_before: the earliest suspend) and a message, or operation when a suspend was already in progress. Not with wait or durable (invalid_arguments). The server's instructions ask the agent to call it when it finishes its work. workspace_status shows a pending request as workspace.suspend_request. |
workspace_suspend_progress |
workspace_key, operation_id |
(0.19.0+) A suspend operation's live progress, read without waking the workspace: {progress} with phase, phase_started_at, cancelable and safe_action. |
workspace_suspend_cancel |
workspace_key, operation_id, wait (default true) |
(0.19.0+) Cancels a suspend before its capture starts; the workspace keeps running as it was. Returns {operation, progress} once the operation is canceled (suspend_canceled), or, with wait: false, as soon as the host accepts. Once capture has started the suspend completes (suspend_capture_started): wait for it, then resume. |
workspace_resume |
workspace_key, wait (default false) |
Resumes a suspended workspace. (0.6.0+) The result includes lost_suspend when the resume's result has it (lifecycle). (0.7.1+) It includes host_lost the same way, with a notice for the agent (lifecycle). |
workspace_fork |
workspace_key, new_key, cpu_millis, memory_mib, disk_gib, memory_mib_held (0.7.0+), wait (default false) |
Forks into a new key. allocation_mode is deprecated: accepted and ignored. Returns {operation, workspace}; (0.6.0+) with durable and durability for a fork of a running workspace. |
workspace_expose_port |
workspace_key, port |
(0.8.0+) Serves a TCP port of the workspace at its own private HTTPS URL (inbound ports). Returns {port, url, created_at, callback, newly_exposed}. The server listens on 0.0.0.0:<port>. Idempotent. |
workspace_list_ports |
workspace_key |
(0.8.0+) The exposed ports: {ports: [{port, url, created_at, callback}]}. |
workspace_port_link |
workspace_key, port, path (default /), ttl_seconds (60-604800, default 86400) |
(0.8.0+) A link that opens the port in a browser: {url, expires_at}. Anyone with the link can open the port until it expires. |
workspace_close_port |
workspace_key, port |
(0.8.0+) Closes the port: its links stop working at once. |
workspace_resize |
workspace_key, memory_mib, memory_mib_held, cpu_millis, disk_gib (at least one) |
(0.8.0+) Resizes the workspace, running or suspended, without a restart, and stores the new caps. allocation_mode is deprecated: accepted and ignored. Returns per resource what applied and when (applies_at: now, resume or next_start), the stored caps and a one-line message. |
volume_open |
name, quota_gib |
(0.12.0+) Creates or reuses a project volume by name, default 1 GiB. Shared volumes stay outside workspace snapshots and forks. |
operation_wait |
operation_id, durable (0.6.0+, default false) |
Keeps waiting for a lifecycle operation, up to the call's deadline. With durable: true, a suspend or fork also waits until its checkpoint is in durable storage. |
usage_summary |
organization_id (default: the key's organization) |
Usage of the organization in the current billing period: meters, allowances with their cap state, allowance_exhausted with exhausted_reason, and spend_cap (0.4.1+), the opt-in overage state, cap, charges and lines per allowance. (0.18.0+) gpu on plans with GPU-hours: hours used, included, past the allowance and billed, cap_state and blocked_reason; at gpu_blocked only the GPU stops and workspaces keep running. The description tells the model about them (0.4.0+). |
workspace_set_computer_use |
workspace_key, state (on, off, inherit) |
(0.9.0+) Switches computer use on or off for the workspace, or back to its template's setting. Returns {enabled, workspace, template, available}. |
workspace_computer_desktop |
workspace_key, action (status, start, stop), width, height |
(0.9.0+, permission computer) The workspace desktop's status, a start at a screen size (640x480 to 2560x1600), or a stop. |
workspace_computer_stream |
workspace_key, interactive, ttl_seconds, stop |
(0.9.0+, permission computer) A link to watch the desktop live, or use it with interactive: true: {url, expires_at, port, interactive}. stop: true ends every view. |
template_get |
slug, version, owner (platform or organization) |
(0.3.0+) A template's versions with their settings (env, inputs, start commands, services, defaults). With version, also that version's recipe in request form. |
template_languages |
base (<slug>@<version>) |
(0.3.0+) The languages and versions a base offers build.languages. |
send_feedback |
message (any length, 0.26.2+), category (bug, confusing, missing, idea, praise, other), user_approved, workspace, request_id, error_code, command |
(0.19.0+) Previews feedback; explicit approval via user_approved: true sends it. See Feedback. Approved result: {id, received_at, duplicate, note}. |
template_build |
template_slug, exactly one of file or recipe, display_name, description, publish (default false), wait (default false) |
(0.3.0+) Builds a version of an organization template from a recipe v2: recipe (the document) or file (a template.yaml or .json path). Local from paths are uploaded first (folders as a tar). Every local path must resolve inside the server's working directory; others are refused before any request. Unpublished unless publish: true. Returns {build, uploads}. |
workspace_resize accepts at_least: true (0.10.0+) to grow named resources independently and wait: false to
return the held answer with its pending operation. The default waits for completion.
Deleting a workspace is deliberately not exposed to agents; use the CLI or the console.
Feedback
(0.19.0+) Local and hosted MCP both use user-directed feedback. Omitted or false user_approved returns {sent: false, authorization_required: true, preview, note} without submitting. Show the exact message and context to the user, then obtain explicit authorization before calling with the same content and user_approved: true. Earlier local versions encouraged proactive feedback; feedback: 'proactive' is now a deprecated alias for the consent policy.
Agents: report only when your user asks to send feedback. Show the exact message and context first, then obtain explicit authorization. A failure or request for a feature is not consent. Leave out private data, secrets and code the user did not mean to share; paraphrase, never paste transcripts. Tell the user what was sent.
- The server adds
client: shardflux-mcp/<version>and, asagent, the MCP client's name and version frominitialize(elseSHARDFLUX_AGENT_LABELwhen it is not the default). A pinned server fillsworkspacewith its key. duplicate: true: the same message from this key in the last 24 hours; it is not emailed again.- Any API key may send it (no tool permission), so it is always listed. It is rate limited: 10 per 10 minutes and 50
per day per key, 200 per day per organization (
rate_limitedwithdetails.retry_after_seconds, and ahintnaming the wait and the fallback address, shardflux@shardflux.dev). - Anything shaped like an API key, token or private key is redacted before the message is stored or emailed.
Workspace tools
These are the TypeScript SDK's workspaceTools(), published with the SDK's JSON Schemas plus workspace_key and,
where the SDK schema has none, timeout_ms:
| Tool | Permission | Arguments (required in bold) |
|---|---|---|
exec |
exec |
command (run with bash -lc), cwd (absolute; a relative one is an invalid_cwd error), timeout_ms, stdin, background (0.7.0+), resource_hint (auto, light or heavy) (0.8.0+) |
exec_read |
exec |
(0.7.0+) session_id, stdout_offset, stderr_offset, wait_ms |
exec_cancel |
exec |
(0.7.0+) session_id, grace_ms |
read_file |
files |
path, offset, length |
write_file |
files |
path, content, append, create_parents |
list_files |
files |
path, limit |
search_files |
files |
(0.4.0+) path, pattern, regex, case_insensitive, include, exclude, max_matches, context_lines. Read-only. |
edit_file |
files |
(0.4.0+) path, edits ({old_text, new_text, replace_all}), expected_revision |
list_processes |
process |
none |
signal_process |
process |
pid, signal |
terminal_open |
pty |
command, rows, cols |
terminal_send |
pty |
session_id, input |
terminal_read |
pty |
session_id, offset, wait_ms |
terminal_close |
pty |
session_id |
git_clone |
git |
url, path, branch, depth |
git_status |
git |
path |
git_commit |
git |
path, message |
browser_screenshot |
browser |
url, width, height. Returns an MCP image content block. |
browser_content |
browser |
url, format (text or html) |
computer (0.9.0+) |
computer |
action (a computer toolset member), coordinate, start_coordinate, region, text, scroll_direction, scroll_amount, duration, repeat; screenshot, settle_ms, format, quality. Its screenshot comes back as an MCP image content block. |
computer_batch (0.9.0+) |
computer |
actions (1-50 objects with the computer tool's action parameters); screenshot, settle_ms, format, quality. Each image (a zoom's, the screenshot after the batch) comes back as an MCP image content block. |
The argument details are in the TypeScript SDK reference. For exec,
timeout_ms is both the call's deadline and the command's timeout: it defaults to, and is capped by, the server's
per-call deadline, and the command is killed 2 seconds before the deadline so its output comes back. (0.7.0+) With
background: true the call returns session_id at once and timeout_ms is the command's own limit (up to 24
hours): read it with exec_read, stop it with exec_cancel (processful workspaces). (0.4.1+) A
command that could not start (a cwd that is not a directory, a program not on PATH) returns exit_code: null and
error (code, message, reason: "exec_failed_to_start") with the workspace's reason, as a failed file-first
execution does.
With SHARDFLUX_TEMPLATE set (0.9.0+), a workspace tool (exec, workspace_exec_start and the file, process,
terminal, git and browser tools) called with a key that has no workspace yet creates it from that template, so the agent
needs no workspace_open call first; that result carries workspace_created: true and the open's timing. Without
SHARDFLUX_TEMPLATE (and on the hosted endpoint), a key that was never opened is not_found: call workspace_open
first.
(0.4.0+) search_files searches file contents and edit_file replaces exact text; without an
expected_revision, edit_file reads the file's revision first, so a concurrent change fails the edit
(conflict, reason: revision_mismatch) instead of being overwritten. See Search and edit
files. If a workspace does not offer them, the call
gets conflict, reason: host_feature_unavailable (details.feature), retryable: false, and a hint naming the
fallback (exec with grep; read_file then write_file).
File-first workspaces
(0.4.0+) workspace_open with mode: "file_first" (or SHARDFLUX_WORKSPACE_MODE=file_first) opens a
file-first workspace: a versioned file tree under /home/user with no VM between calls. It is
ready at once and never suspended.
execruns each command as an execution: a fresh VM on the workspace's files. Only files under/home/userpersist between calls. The result addsexecution_id,state,tree_revisionandchanged(up to 200 paths,changed_truncated). An execution runs to completion: when the call's deadline passes first, the error carries itsexecution_id, and the execution continues server side.- The files tools work as on a processful workspace; each change publishes the next tree revision.
- The process, terminal, git and browser tools and
workspace_suspend,workspace_resume,workspace_forkandoperation_waitdo not apply. A pinned server lists only the tools of its workspace's mode (once it is known, elseSHARDFLUX_WORKSPACE_MODE, else processful) and sendsnotifications/tools/list_changedwhen that changes what it listed. An unpinned server lists every tool and refuses one the named workspace's mode lacks before any request (conflict,reason: not_supported_for_mode, with ahint).
Results
A successful call returns the result as JSON text content and as structuredContent. Workspace results include id,
key, ready, observed_state, desired_state, template (slug, version and, 0.7.0+, immutable_version:
the version its immutable paths show), active_operation, pending_reason, failure (0.27.1+: a
failed workspace's reason, the error of the operation that failed it; else null), lifetime,
purpose, disk_layout, idle_timeout_seconds, ended_reason, startup (0.3.0+: the state of the template's
start commands and services; failed names the step, its exit code and output tail), and mode and, for a file-first
workspace, tree_revision (0.4.0+), suspend_request (0.4.1+: a pending suspend when idle, else null), and
memory (0.7.0+: allocation_mode, promised_mib, held_mib, plugged_mib). An exec result adds memory_grow
(0.7.0+) when the command's start grew the workspace's memory. Tool tokens are never returned to the model.
Permissions
tools/list shows the management tools and the workspace tools the API key's tool permissions allow (exec,
files, pty, process, git, browser), read from GET /v1/me. If the server cannot read them, it lists every
workspace tool and logs a warning; a call the key may not make is then refused by the API.
Choose the key's permissions to match what the agent should be able to do: for example, a key with only files gives
the agent read_file, write_file, delete_file (0.23.0+) and list_files and no command execution.
Account actions
Registering, signing in, organizations, projects, API keys, members, invitations, billing and plan upgrades, spend
alerts and the audit export are not tools. The server authenticates with a project API key, and the API refuses a
project API key for them: 403 forbidden ("API keys cannot perform this action.") on the account routes, 401 on the
/v1/auth session routes. They need a person's session. (0.4.0+) The server instructions tell the agent to use the
shard CLI for them (shard --help; for example
shard auth login, shard setup, shard billing upgrade <plan>), which signs a person in with a CLI session.
Pinning
With SHARDFLUX_WORKSPACE_KEY set, the server works on that one workspace:
workspace_keybecomes optional on every tool and defaults to the pinned key.- A different key is refused with
code: workspace_pinned(details.pinned_workspace_key). workspace_openopens (or creates) the pinned workspace.
Pin a workspace when an agent should have one computer and nothing else, for example a per-project scratch workspace.
Wake on use
Workspace tools resume a suspended workspace, then run:
- A suspended workspace is resumed (or the resume or open already running is joined), and the call runs once it is running. A call made during a suspend or resume waits for it to finish. The call never runs twice: the refused attempt did nothing.
- The wait is bounded by
SHARDFLUX_WAKE_TIMEOUT_MSand the call's deadline. Past it the result iscode: timeoutwith theoperation_idandlast_stateof the resume or open, and (0.15.0+)last_reason,deadline_atandqueue_positionwhen the operation reports them. That operation continues server side:operation_waitkeeps waiting. - (0.15.0+) A call refused before it ran because room is being made for it, on the workspace's host (503
host_capacity,details.queue_position) or in the plan's workspaces working at once (429quota_exceeded), is sent again after eachRetry-Afteruntil shortly before the call's deadline. A refusal that lasts is the error withretry_after_secondsand ahint; a deadline reached while waiting iscode: timeoutwithreason,queue_positionandretry_after_seconds. Nothing ran. - A resume or open that fails returns
code: operation_failed(retryable: trueforcapacity_unavailable; the workspace stays suspended). - With
SHARDFLUX_WAKE=offthe refusal comes back instead:conflictwithdetails.reason: workspace_not_running, orworkspace_not_runningfrom the cell gateway. - (0.4.0+) The wake is one request: the API holds the resume until the workspace runs and answers with this
server's tool token, so the tool runs at once.
workspace_resumewithwait: truesends the same request. The wake'stimingis onerequest(held)phase. - (0.4.0+)
read_file,list_filesandsearch_filesof a suspended workspace are answered from its saved disk without waking it: the files as they were at the suspend. - (0.4.0+) Every other workspace tool call first sends a wake hint without waiting for it, so a workspace its host has parked while idle starts waking, and a suspended one starts resuming, while the call is prepared.
Deadlines and cancellation
- Every call has a deadline:
timeout_ms, clamped toSHARDFLUX_MCP_TOOL_TIMEOUT_MS. Waits time out just before it withcode: timeoutand theoperation_id; the operation continues server side. Any request still in flight at the deadline is aborted. - A queued open, resume or fork (
capacity_pending) has a deadline 15 minutes after it was created, moved later while new capacity is starting for it (start deadlines). A wait that ends first returnscode: timeout, and its message names the deadline; the start keeps its place, andoperation_waitkeeps waiting. Past the deadline, the start fails:operation_failedwithdetails.error_code: capacity_unavailableandretryable: true; nothing was started. - Progress (0.15.0+). A request with
_meta.progressTokengetsnotifications/progresswhile its call waits: on each change and at least every 10 seconds, with amessagesuch asQueued for capacity (position 3); a new host is starting, ready by 21:40Z(an open, resume, fork, wake oroperation_waitof a queued start),Waiting for room on the workspace's host (position 2)orWaiting for a free working slot: ...(a tool call waiting to be admitted), or the lifecycle phase.progresscounts up; there is nototal. A request without a token gets none. Clients that reset their request timeout on progress keep long waits alive this way. - MCP
notifications/cancelledaborts the work behind the call: waits, requests to the API and the cell gateway, and backoff sleeps. No response is sent and the server stays up. A lifecycle operation that was already started is not canceled.
Errors
Errors are tool results, never protocol failures: isError: true and
structuredContent.error = {code, message, status, request_id, retryable, operation_id, details, source}, plus
reason (the refusal's details.reason) and, (0.4.0+) for the file-first refusals and
host_feature_unavailable, a hint saying what to do instead. The only protocol error is an unknown tool name
(InvalidParams).
(0.4.0+) An unexpected failure also carries structuredContent.feedback: a suggestion to preview send_feedback and obtain explicit approval before sending, with
category bug, the request id and the error code. The expected flow has none: invalid_arguments,
workspace_pinned, unauthenticated, validation_failed, timeout, and refusals whose error names the next step (a
stale revision, an edit that does not match, a mode the workspace lacks, a feature the workspace does not offer).
code |
Meaning |
|---|---|
| An API or cell gateway code | The API or the workspace refused the call. source is api or cell. |
invalid_arguments |
The arguments do not match the tool's schema (issues lists the problems), or a local path of template_build is outside the working directory. Nothing was sent. |
workspace_pinned |
A different key than the pinned one. |
not_found |
No workspace with that key in the project. |
timeout |
The call's deadline or the wake timeout passed. operation_id and last_state name the operation, which continues; (0.15.0+) last_reason, deadline_at and queue_position when it reports them. retryable is true. |
operation_failed |
The operation ended failed or canceled. details.error_code (and details.reason) say why; retryable is the operation error's own flag. |
upload_failed |
The storage refused a template_build upload (details.sha256, details.storage_code). |
network_error |
The API or the cell gateway could not be reached (retryable: true). |
protocol_error |
A response was not the documented shape. |
internal_error |
An unexpected failure in the server (also logged). |
A start refused because an allowance is used up is allowance_exhausted (402) with reason allowance_used (upgrade,
or turn on overage), overage_paused (a plan payment is past due) or spend_cap_reached (raise the spend cap or
upgrade), and details.spend_cap. An owner or billing member acts on it in the console; retrying does not help. See
402 allowance_exhausted.
A feature the plan does not include is entitlement_required (402) with reason not_included, for example the GPU
(GPU needs the Startup or Scale plan.). (0.18.0+) Its hint says an owner or billing member upgrades, naming
the plans the refusal lists; retrying does not help.
Timing
A call that opens a workspace or waits says where the time went, compacted for model context:
{
"timing": {
"action": "resume",
"outcome": "succeeded",
"operation_id": "01a0ead6-bd61-737a-ae88-66e2d01a6e25",
"total_ms": 413,
"phases": ["request 218 ms", "queued 195 ms"],
"server": { "queued_ms": 51, "run_ms": 290, "total_ms": 341, "resume_path": "local_cache" },
"outside_server_ms": 72,
"retries": 0
}
}workspace_openandoperation_waitalways carry it;workspace_suspend,workspace_resumeandworkspace_forkcarry it withwait: true; workspace tools carry it when they had to wake the workspace (action: "wake").- Phases are in order, as
phase(reason) ms.request(held)means the API held the open until the workspace was ready. serveris the operation's own queued, run and total time plus the start or resume path;outside_server_msis everything else (network, polling, reading the workspace, the tool token).- A failed or timed-out call carries it too, next to
error.
Logging
Logs are JSON lines on stderr (stdout is the protocol), filtered by SHARDFLUX_MCP_LOG_LEVEL. Each line has
time, level, service: "shardflux-mcp" and message, plus fields such as tool, outcome, ms and
request_id. The first line (ready) records the version, API URL, pinned key, default template, agent label and
timeouts. The API key is never logged, and anything shaped like a key is redacted. The server shuts down when the
client closes stdin, or on SIGINT or SIGTERM.
Updates
(0.4.0+) At startup, after the configuration is validated, the server checks whether @shardflux/mcp at its
version is current: the latest release from npm (0.15.0+; SHARDFLUX_NPM_REGISTRY names another registry) and the
oldest supported one from the API's GET /v1/client-versions. Both requests (3 s timeout) run in the background: the
MCP handshake and tool calls never wait for them, and any failure is ignored. When the server is outdated, or below the
oldest version the API still supports, it logs one warn line on stderr:
The notice includes status, package, current, latest, minimum_supported, upgrade_command and release_notes_url; its versions come from the update check.
- An unsupported server says
... is no longer supported by the Shardflux API (minimum <version>). Update: ...("status":"unsupported"). It keeps running. - Otherwise it stays silent (one
debugline), also when the API does not answer. - The notice is not in the server instructions: they are fixed when the server starts, and the handshake does not wait for the check.
SHARDFLUX_NO_UPDATE_CHECK=1orNO_UPDATE_NOTIFIER=1turns the check off.- The
@shardflux/sdkclient inside the server runs no check of its own: the update to install is the server's.
Compatibility
Breaking changes to tools and results ship only in minor releases and are marked Breaking in the changelog. Tool results are the API's objects summarized for model context; new fields can appear in any release.
Integration controls (0.6.0+)
workspace_open accepts labels and idle_policy; workspace_list filters labels. New controls: workspace_idle, workspace_keepalive, workspace_set_idle_policy (default clears inheritance), workspace_set_labels, workspace_exec_start with stdin_open and (0.7.0+) timeout_ms (read it with exec_read, stop it with exec_cancel), and workspace_exec_input with offset and optional close. The last two require exec permission and processful mode; pipe frames are at most 64 KiB. Use each acknowledged byte offset, including partial writes.
Node 26 uses the SDK's private HTTP/1.1 pool. Protocol errors include source. Failed workspace IDs can recover through resume.
Prepare an imminent tool call (0.8.0+)
Set SHARDFLUX_PREWAKE=on (default off) to offer workspace_hint. A host that observes model tool-input streaming can invoke it with workspace_key ahead of a VM tool call. It stages a parked workspace without waiting for restore; resume a suspended workspace first. File-first workspaces do not list this tool.
Viewer link reuse and environment URL (0.10.0+)
workspace_computer_stream reuses a link of the same kind with more than 60 seconds left. fresh: true mints a
new link; stop: true clears it. computer_batch returns a final screenshot or zoom image once.
SHARDFLUX_BASE_URL aliases SHARDFLUX_API_URL; the latter wins. Environment HTTP(S)_PROXY and NO_PROXY are honored.
Upgrade in place (0.10.0+)
workspace_upgrade accepts workspace_key and at (now or next_resume). The cold start keeps files, installed
package files and home, and ends memory and processes. The operation reports whether the target is scheduled or
applied. Workspace summaries expose upgrade_available and upgrade_pending.
Saved site logins (0.26.2+)
On your laptop, site_logins_list({ site?, project_id?, organization_id? }) returns metadata.
site_login_add({ site, username?, organization_id? }) returns waiting with a secure entry URL to give
to your user. Their password goes from that page directly to the encrypted store. List logins after they
save; values stay outside tool arguments and results. The server uses the CLI's saved session for its
API URL, or SHARDFLUX_SESSION_TOKEN. Its secure entry page ships with the package through
@shardflux/cli, so no global CLI installation is needed.
credential_fill takes an optional account username and the passkey field.
Credential account creation (0.27.2+): after your user selects it, call needs_you_answer with decision: "create_account". The requesting agent receives that choice and creates the account, storing credentials securely. Do not put secret values in the tool arguments.