@shardflux/mcp: shardflux-mcp
New accounts can register and create organizations, projects and API keys automatically. Starting workspace compute requires either a paid plan ($9/mo Developer and up) or the 7-day Pro signup trial: verify an established GitHub account (at least 30 days old) or non-disposable work domain (registered at least 30 days ago with active MX records), and complete a non-prepaid, non-wallet $0 Stripe card check (shard billing trial --wait or Usage & billing). One trial per person, card and GitHub account across all accounts, ever. After the trial ends, workspace compute requires a paid plan while up to 10 GiB of retained workspace storage is kept.
Serverless VMs without lifecycle code.
Give each customer of your product a persistent computer for their agent: open a workspace by a key you choose
(customer-42/main) and the same key returns the same Linux microVM, with its files, tools and running processes. It
parks seconds after its last call, wakes on the next call or HTTPS request, and you pay for the compute it uses while
Shardflux manages the infrastructure.
This package is the Shardflux MCP server. It gives the agent inside your product, or any MCP
client, Shardflux workspace tools: run commands, read and edit files, use git, terminals, a browser and a desktop,
expose ports, and suspend, resume or fork a workspace. Your app keeps its own identity, model calls and agent loop;
Shardflux is the computer underneath.
It runs locally over stdio (or hosted at https://mcp.shardflux.dev/mcp) and uses
@shardflux/sdk with the scoped project API key you give it. Each tool
call becomes one SDK request or wait:
- it has no agent loop of its own;
- it keeps no local workspace directory;
- it keeps no state beyond per-key workspace handles, so tool tokens are reused between calls.
What your agent gets:
- Workspaces by key.
workspace_open creates a workspace on first use and reconnects to it afterwards; it never
resets it.
- Park and wake on use. A workspace tool call resumes a suspended workspace and then runs;
workspace_suspend with
after_seconds parks it once the agent is done.
- Suspend, resume and fork. A resume restores memory and running processes;
workspace_fork copies a workspace to
a new key.
- Elastic memory and live resize. A workspace holds the memory its commands use and grows when they need more.
- Templates, ports and computer use. Build templates from a recipe, serve a port at a private HTTPS URL, and drive
a desktop with the
computer tool.
- File-first workspaces and shared volumes. A versioned file tree with a fresh VM per command, and volumes mounted
into many workspaces.
Plans, sizes and regions: docs.shardflux.dev/limits. Documentation:
https://docs.shardflux.dev/reference/mcp.
Compatibility. The API is versioned (/v1). Breaking changes ship only in minor releases and are marked
Breaking in the changelog.
Runtime security
Runs on Node.js 24.22.1 or 26.12.1 and later releases in each line. Updating the npm package does not replace Node.js.
Install and run
Requires Node.js 24 or later and a Shardflux project API key (sfk_..., from the Shardflux console).
MCP clients start the server themselves (see "Client setup"). The command is:
npx -y @shardflux/mcp
with SHARDFLUX_API_KEY in its environment. To try it by hand:
SHARDFLUX_API_KEY=sfk_... npx -y @shardflux/mcp
It logs one JSON ready line on stderr and then waits for MCP messages on stdin (stdout is the
protocol). Close stdin or press Ctrl-C to stop it.
Or install it globally and use the shardflux-mcp command instead of npx -y @shardflux/mcp:
npm install -g @shardflux/mcp
Quick start
-
Get a project API key. Sign up at app.shardflux.dev/signup: the console opens
on Setup with your first key. Or from a terminal with the shard CLI:
npx -y @shardflux/cli@latest signup --email you@example.com
eval "$(npx -y @shardflux/cli@latest env)"
-
Add the server to your MCP client (see "Client setup"):
{
"mcpServers": {
"shardflux": {
"command": "npx",
"args": ["-y", "@shardflux/mcp"],
"env": { "SHARDFLUX_API_KEY": "sfk_..." }
}
}
}
-
Your agent opens a workspace by key, runs a command, writes and reads a file, and parks the workspace when it is
done. These are the tool calls it makes:
{"name":"workspace_open","arguments":{"workspace_key":"customer-42/main","template":"python-node-browser"}}
{"name":"exec","arguments":{"workspace_key":"customer-42/main","command":"python3 --version"}}
{"name":"write_file","arguments":{"workspace_key":"customer-42/main","path":"/home/user/notes.txt","content":"hello"}}
{"name":"read_file","arguments":{"workspace_key":"customer-42/main","path":"/home/user/notes.txt"}}
{"name":"workspace_suspend","arguments":{"workspace_key":"customer-42/main","after_seconds":60}}
The next call on customer-42/main resumes the same workspace, with its files and processes.
{"name":"workspace_fork","arguments":{"workspace_key":"customer-42/main","new_key":"customer-42/experiment"}}
copies it to a new key.
Client setup
Local server (stdio)
Any MCP client that starts stdio servers takes the standard mcpServers entry. It registers the server as
shardflux; replace sfk_... with your key, and add any other variable from "Configuration" to env the same way:
{
"mcpServers": {
"shardflux": {
"command": "npx",
"args": ["-y", "@shardflux/mcp"],
"env": { "SHARDFLUX_API_KEY": "sfk_..." }
}
}
}
A client configured field by field takes command npx, arguments -y @shardflux/mcp and environment
SHARDFLUX_API_KEY. When your client expands environment references in its config, read the key from the
environment instead of committing it to a project file.
workspace_open waits until the workspace is ready, up to the server's per-call deadline
(SHARDFLUX_MCP_TOOL_TIMEOUT_MS, default 120000 ms). Keep your client's tool timeout above it, and allow about 30 s for
the first start, which downloads the package.
Hosted endpoint
The same server runs at https://mcp.shardflux.dev/mcp (MCP Streamable HTTP with OAuth). Add the URL to any MCP client
that supports remote servers, sign in, choose the project the client works in, and select Connect. The connection
is a project API key named <client> (MCP connector), listed on the project's API keys page in the console; revoke
it there to disconnect. The hosted server has no local files: template_build takes the recipe inline.
Use as a library
The package also exports the server for other MCP transports, so you can embed it in your own agent:
import { createShardfluxMcpServer, loadConfig } from '@shardflux/mcp';
const server = createShardfluxMcpServer(loadConfig(process.env));
await server.connect(transport);
Configuration (environment)
SHARDFLUX_API_KEY | Scoped project API key. Required. Its tool permissions decide which workspace tools are listed. |
SHARDFLUX_API_URL | Default https://api.shardflux.dev. Plain http:// is allowed only for loopback hosts. |
SHARDFLUX_WORKSPACE_KEY | Pins one workspace. workspace_key becomes optional on every tool, and a different key is refused with workspace_pinned. |
SHARDFLUX_TEMPLATE | Default template for workspace_open. (0.9.0+) Also lets a workspace tool create its workspace: a workspace_key with no workspace yet is created from this template on first use (default is the platform default template). |
SHARDFLUX_WORKSPACE_MODE | (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 | Default and maximum deadline per tool call, 1000-3600000 ms. Default 120000. A call's timeout_ms can only shorten it. |
SHARDFLUX_PREWAKE | 0.8.0+: on offers explicit workspace_hint; default off adds no early hint tool. |
SHARDFLUX_WAKE | on (default) or off. On: workspace tools resume a suspended workspace and then run (see "Contract"). Off: they return the workspace_not_running refusal. |
SHARDFLUX_WAKE_TIMEOUT_MS | Longest wait per tool call for a workspace to wake or finish a transition, 1000-3600000 ms. Default 120000. It is clamped to SHARDFLUX_MCP_TOOL_TIMEOUT_MS, and each wake also ends 250 ms before the call's own deadline. |
SHARDFLUX_AGENT_LABEL | Attribution label of every tool token this server obtains. Default mcp. It appears as an agent session in GET /v1/workspaces/{id}/agent-sessions, the console and shard ws sessions. |
SHARDFLUX_MCP_TOOLS | all lists every tool. Unset (or used): the tools for the features the key's organization uses, read from the API once at startup. |
SHARDFLUX_MCP_LOG_LEVEL | debug, info (default), warn or error. Logs are JSON lines on stderr; stdout is the protocol. The key is never logged, and anything key-shaped is redacted. |
SHARDFLUX_HTTP_KEEPALIVE | 0.6.0+: default private HTTP/1.1 pooling on Node 26; 0 forces close for diagnosis, 1 uses native pooling. |
SHARDFLUX_NO_UPDATE_CHECK | (0.4.0) 1, true, yes or on turns off the startup version check (see "Updates"). |
NO_UPDATE_NOTIFIER | (0.4.0) The npm convention: any non-empty value also turns the check off. |
Invalid configuration exits with code 2 before serving, with one JSON line on stderr, for example:
{"time":"2026-09-28T20:18:25.654Z","level":"error","service":"shardflux-mcp","message":"configuration error: SHARDFLUX_API_KEY is required (a scoped Shardflux project API key)"}
template_build reads local files (file, and from paths in a recipe) only inside the server's
working directory: the directory your MCP client starts it in.
Tools
The management tools:
workspace_open | Open by key: create on first use, reconnect or resume afterwards, never reset. Waits until the workspace is ready (its template's start commands and services included) unless wait: false. lifetime: "session" opens a workspace that is discarded after its idle timeout. inputs (0.3.0) passes the template's text inputs, {"NAME": "value"}. mode (0.4.0): processful or file_first (see "File-first workspaces"). allocation_mode and memory_mib_held (0.7.0): see "Elastic memory". like and volumes (0.12.0): see "Shared volumes". |
workspace_list | List the project's workspaces, with prefix, state, lifetime, purpose, include_deleted, limit and cursor. By default only persistent standard workspaces are listed. |
workspace_status | One workspace plus its five most recent operations. |
workspace_suspend, workspace_resume | Lifecycle operation. Returns at once unless wait: true (then once it finished, through the SDK's own wait). |
workspace_suspend with after_seconds | (0.4.1) Suspend when idle: the workspace is suspended once it has been idle for after_seconds (0-3600; 0 = as soon as it is idle, 0.5.1+), instead of now. The description tells the agent to use it when it finishes its work, so the workspace stops using RAM soon after. Its next tool call on the workspace cancels it; a running command or a keepalive postpones it. Returns suspend_request (not_before: the earliest suspend) and a message; operation when a suspend was already in progress. Not with wait. workspace_status shows a pending request as workspace.suspend_request. Not for file-first workspaces. |
workspace_suspend with durable: true | (0.6.0+) Returns once the suspend is in durable storage. A suspend returns as soon as the workspace is sealed, typically in a few hundred ms; its operation's durable turns true when the copy lands in durable storage, typically within a second (durability shows its progress). |
workspace_fork | Fork into new_key. A fork of a running workspace carries durable and durability the same way (0.6.0+). Without caps the fork keeps the source's caps and memory allocation (allocation_mode, memory_mib_held: 0.7.0+). With wait: true the API holds the fork until the copy runs and returns it ready in the same request (0.7.0+). |
workspace_resize | (0.8.0) Change a workspace's memory, CPU or disk without a restart, running or suspended: memory_mib, memory_mib_held, allocation_mode, cpu_millis, disk_gib (at least one). Returns per resource what applied and when (applies_at: now, resume or next_start), the stored caps and a one-line message. See "Resize". |
operation_wait | Keep waiting for an operation. durable: true (0.6.0+): a suspend or fork, until its copy is in durable storage. |
workspace_expose_port, workspace_list_ports, workspace_close_port, workspace_port_link | (0.8.0) Serve a port of the workspace at its own private HTTPS URL, list the exposed ports, close one, and get a link that opens one in a browser. See Inbound ports. |
workspace_set_computer_use, workspace_computer_desktop, workspace_computer_stream | (0.9.0) Switch computer use on, off or to the template's (state); report, start at a screen size or stop the desktop; and get a link to watch or use it live. See Computer use. |
volume_open, volume_list | (0.12.0) Create or reuse a project volume by name, and list the project's volumes. See Shared volumes. |
usage_summary | The organization's usage summary for the current period: meters, allowances with their cap state, allowance_exhausted with exhausted_reason, and (0.4.1+, an API with opt-in overage) spend_cap: the overage state, cap, charges, lines per allowance and the date the cap is projected to be reached. (0.18.0+) gpu on plans with GPU-hours: hours used, included, past the allowance and billed, cap_state and blocked_reason. See /limits. |
seats_get | (0.28.0+) Seats of the organization's per-seat plan: plan_per_seat, seat_plan_key (null: the organization has no seats), purchased, assigned, available, price_usd_per_seat, assignments and auto_assign. Read-only; owners, admins and billing members change seats in the console or with shard billing seats. |
send_feedback | (0.19.0+) Preview feedback; user_approved: true sends after explicit user authorization: message, category, and optional workspace, request_id, error_code, command. See Feedback. |
template_get | (0.3.0) A template's versions with their settings (env, inputs, start commands, services, defaults) and (0.7.0) their immutable paths; with version, that version's recipe in request form. |
template_languages | (0.3.0) The languages and versions a base (<slug>@<version>) offers build.languages. |
template_build | (0.3.0) Build a version of an organization template from a recipe v2: recipe (the document) or file (a template.yaml or .json path). File entries may name local from paths, 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; wait: true follows the build within the call's deadline. |
More workspace tools are described with their feature: Integration controls,
Suspension progress and cancellation,
Idle deletion retention and Workspace upgrade.
The SDK's workspace tools come from workspaceTools():
exec, exec_read, exec_cancel (0.7.0+: background commands)
read_file, write_file, list_files, and search_files, edit_file (0.4.0+), delete_file (0.23.0+),
read_sealed_files (0.11.0+)
list_processes, signal_process
terminal_open, terminal_send, terminal_read, terminal_close
git_clone, git_status, git_commit
browser_screenshot, browser_content
computer, computer_batch (0.9.0+: the workspace desktop, while its computer use is on)
They are published with the SDK's JSON Schemas verbatim, plus workspace_key and, where the
SDK schema has none, timeout_ms. They are filtered by the key's tool permissions when the server
can read them; otherwise it lists every workspace tool. exec's cwd is an absolute path (default
/home/user): a relative one is an error result with details.reason: invalid_cwd whose message names the absolute
path it likely means, and a command that could not start (a cwd that is not a directory, a program not on PATH)
returns exit_code: null with error: { code, message, reason: "exec_failed_to_start" } naming the workspace's
reason (0.4.1+). browser_screenshot returns an MCP image content block. search_files is annotated read-only;
edit_file replaces exact text and, without an expected_revision, reads the file's revision first so a concurrent change fails the
edit (conflict, details.reason: revision_mismatch) instead of being overwritten.
Each workspace tool call first sends the wake hint (POST /wake-hint, without waiting for it): a parked workspace
starts restoring while the call is prepared, and a suspended one starts resuming. read_file,
list_files and search_files send none (0.4.0+): a suspended workspace is read from its saved disk,
listed and searched there without resuming it (the state at suspension).
If search or patches are not available for a workspace, search_files and edit_file fail with conflict,
reason: host_feature_unavailable (details.feature file_search or file_patch), retryable: false and a hint
naming the fallback (exec with grep; read_file then write_file).
Deleting a workspace is deliberately not exposed to agents; use the
CLI or the console.
Account-level actions are not tools either: registering, signing in, organizations, projects, API keys, members,
invitations, billing and plan upgrades, spend alerts and the audit export. 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. From 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.
Setup (0.16.1+): the instructions point the agent to shard setup --guide (CLI 0.17.1+), which lists the setup steps
in order. From 0.19.0 the agent runs the permitted steps and stops an action when a permission system refuses it: it
gives the user the exact command and asks for its non-secret result, without bypassing the refusal; blocked or
unobserved behavior stays unverified. Browser sign-ins and secret-entry pages remain the normal path.
Every tool finds its workspace by exact key across every lifetime and purpose, so sessions, template drafts and test
instances resolve too. The live workspace wins over tombstones that ended sessions left with the same key. Workspace
results include lifetime, purpose, disk_layout, idle_timeout_seconds, ended_reason and (0.3.0) startup:
the state of the template's start commands and services (failed names the step, its exit code and output tail).
Contract
For error codes, retry timing, plan recovery and disk growth actions, see the
error reference.
-
Arguments. They are validated against the published schema with the SDK's validateArgs
before any request. A failure returns isError with code: invalid_arguments and the issues.
-
Errors are tool results. They carry isError: true and
structuredContent.error = {code, message, status, request_id, retryable, operation_id, details, source},
using the API's or cell gateway's closed error codes. They are never protocol failures. The
only protocol error is an unknown tool name (InvalidParams).
- A failed operation is
code: operation_failed with details.error_code (and details.reason when the
operation error has one) and, from 0.2.1, retryable: the operation error's own flag.
- An API or cell gateway the server cannot reach is
code: network_error, retryable: true.
- A start refused because an allowance is used up is
code: allowance_exhausted (402) with reason (0.4.1+):
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.
- (0.28.0+) Compute runs on organizations with a card on file, and saving one charges nothing. An open, resume,
fork, upgrade or template build of an organization without one is
code: card_required (402, retryable: false)
with details.add_card_url (the page where a person saves the card) and a hint that asks the user to save a
card there or with shard billing card --open --wait, then call again.
- (0.4.0+) A failed call has a
feedback field next to error: a one-sentence suggestion to call
send_feedback with category bug, the request_id and the error code. Preview first and obtain explicit user authorization before user_approved: true. Not for invalid_arguments,
workspace_pinned, unauthenticated or card_required. A failed send_feedback carries a hint instead (when to retry, or the
email address).
-
Start deadlines (0.2.1+). A queued open, resume or fork (capacity_pending) has a deadline 15 minutes after
it was created; a wait that ends first returns code: timeout, and its message names the deadline. A start still
pending then fails: operation_failed, details.error_code: capacity_unavailable, retryable: true, and a
message telling the agent that nothing was started and it can retry. The server instructions say the same.
(0.15.0+) A timeout of a wait carries operation_id and last_state, plus last_reason, deadline_at and
queue_position as fields when the operation reports them.
-
Admission queues (0.22.0+, SDK 0.29.0). workspace_open follows the API queue automatically, retaining the same
request body and Idempotency-Key and honoring Retry-After within its existing call deadline.
-
Progress (0.15.0+). A request with _meta.progressToken gets notifications/progress while its call waits: on
each change and at least every 10 s, with a message such as Queued for capacity (position 3) (an open, resume,
fork, wake or operation_wait of a queued start), Waiting for a free working slot: ... (a tool call waiting to be
admitted), or the lifecycle phase (Resuming the workspace: queued). progress counts up; there is no total. A
request without a token gets none. Clients that reset their request timeout on progress keep long waits alive this
way.
-
Waiting for room (0.15.0+). A call refused before it ran while room is made for it (503 host_capacity with
details.queue_position, or 429 quota_exceeded while every workspace the plan lets work at once is busy) is sent
again after each Retry-After until shortly before the call's deadline. A refusal that lasts is the error with
retry_after_seconds and a hint; a deadline reached while waiting is code: timeout with reason,
queue_position and retry_after_seconds, and nothing ran.
-
Plan API budgets (0.20.0+, SDK 0.27.0). Tool errors include rate_limit, retry_after_seconds and a hint naming
the shared scope and delay. The SDK waits for proven pre-handler request refusals within the tool deadline.
Workspace credential budgets retain their own reason and metadata.
-
Credential key pacing (0.20.2+). On plans with API budgets, workspace credentials share organization and
workspace hourly allowances, plus a separate API-key burst. A tool_token_budget refusal can name api_key; honor
Retry-After and reuse valid credentials. It does not promise that lifecycle work has not started, so it never
authorizes replay of an arbitrary POST.
-
Timing (0.2.0+). A call that opens a workspace or waits says where the time went, from the SDK's lifecycle
timing, compact 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_open and operation_wait always carry it. workspace_suspend, workspace_resume and
workspace_fork carry it with wait: true. Workspace tools carry it when they had to wake the workspace
(action: "wake"). Other results do not.
- Phases are in order, as
phase(reason) ms. request(held) means the API held the open (or, 0.7.0+, the fork)
until the workspace was ready. capacity_pending is time queued to start.
server is the operation's own queued, run and total time, plus the start or resume path the cell reported.
A resume also has memory_restored (0.5.0+) when the API reports it, and cold_boot_reason when it is false;
host_lost (0.7.1+) after the machine the workspace ran on failed (restored_from, and state_as_of for a
checkpoint).
outside_server_ms is everything else: network, polling, reading the workspace, the tool token.
- A failed or timed-out call carries it too, next to
error ({error, timing}).
workspace_open uses the SDK's waited open: the API holds the request until the workspace is ready and answers
with the first tool token, which the next tool call reuses.
-
Deadlines. Every call has one: timeout_ms, clamped to the ceiling.
- Waits time out just before the deadline with
code: timeout and the operation_id; the
operation continues server side (a queued start until its deadline, deadline_at in the error).
- Any request still in flight at the deadline is aborted.
exec's command timeout is capped at the deadline minus 2 s, so its output comes back. With background: true
(0.7.0+) the call returns at once and timeout_ms is the command's own limit.
-
Exec survives a dropped connection (0.20.0+). A lost start response is retried with the same session ID and
reattaches to the command that already started, and a cut-off JSON answer is retried within the same safe retry
boundary.
-
Cancellation. MCP notifications/cancelled aborts the SDK work behind the call: waits,
HTTP requests to the API and to the cell gateway, and backoff sleeps. No response is sent, and
the server stays up. The lifecycle operation itself is not canceled.
-
Workspace tools wake suspended workspaces. With SHARDFLUX_TEMPLATE set (0.9.0+), a key that has no workspace
yet is created from that template by the first workspace tool that names it (exec, workspace_exec_start and the
file, process, terminal, git and browser tools), and that result carries workspace_created: true. Without it, a
workspace that was never opened is not_found: call workspace_open first. Reads (read_file, list_files,
search_files) of a suspended workspace are answered from its saved disk
without waking it.
- 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 resume is one request held until
the workspace runs, answered with this server's tool token (0.4.0+, an API with the held resume).
- The wait is bounded by
SHARDFLUX_WAKE_TIMEOUT_MS and the call's deadline. Past it the
result is code: timeout with the operation_id and last_state of the resume or open. That
operation continues server side: operation_wait keeps waiting. A resume or open that fails
returns code: operation_failed (retryable: true for capacity_unavailable: the workspace stays
suspended).
- With
SHARDFLUX_WAKE=off the API's refusal comes back instead (conflict,
details.reason: workspace_not_running, or workspace_not_running from the cell gateway).
- Detecting a cold resume (0.5.0+). A resume restores memory and running processes. After a platform runtime
update, or after the machine the workspace ran on failed (0.7.1+), a resume can boot from the saved disk instead
of restoring memory (a cold boot), also when a workspace tool wakes it; check
memory_restored. The call still
runs with the files kept, and processes start fresh. The result (or the error result) then carries
timing.server.resume_path: "cold_boot", memory_restored: false, cold_boot_reason (guest_filesystem from 0.22.0, runtime_changed or
host_lost) and a notice the agent reads: to start its dev servers, databases, watchers and background jobs
again. The server instructions and the workspace_resume description say so too. With guest_filesystem
(0.22.0+) the reason is in the resume timing, and the notice explains the retained files and restarted processes;
see the workspace lifecycle.
- Workspaces recover by themselves (0.7.1+). When the machine a workspace runs on fails, the workspace is
suspended, and the next tool call on it resumes it. From its own disk it is the cold resume above (reason
host_lost). From its newest checkpoint, the notice names the time its state is from (host_lost.state_as_of
in the operation), so the agent checks the files it changed since.
- Tool tokens are never returned to the model.
-
Keys, not ids. Tools take workspace keys, resolved by exact match within the key's project.
Inbound ports (0.8.0)
An agent can show what it builds: workspace_expose_port serves a TCP port of the workspace at its own HTTPS URL
(https://<port>-<handle>.<domain>) and returns {port, url, created_at, callback, newly_exposed};
workspace_port_link returns a link ({url, expires_at}, path and ttl_seconds 60-604800, default a day) that
opens the port in a browser, for the agent or the person it works for. Every port is private: the URL answers only a
link's browser session, a port token or the port's callback URL. A request wakes a suspended workspace and is
answered once it runs. workspace_list_ports lists the exposed ports; workspace_close_port closes one, and its
links stop working at once. The server inside the workspace listens on 0.0.0.0:<port> (start it with
workspace_exec_start). The refusals port_not_exposed, port_limit and inbound_ports_not_available carry a
hint. Processful workspaces; a pinned file-first workspace does not list these tools.
Embed a live viewer (0.10.0+)
Watch the desktop or a port preview inside your web app. Choose 1–10 distinct HTTPS origins, then use the returned URL as the iframe source.
{"name":"workspace_computer_stream","arguments":{"workspace_key":"acme/demo","embed_origins":["https://app.example.com"]}}
{"name":"workspace_port_link","arguments":{"workspace_key":"acme/demo","port":3000,"embed_origins":["https://app.example.com"]}}
<iframe src="RETURNED_LINK_URL" title="Watch the agent" style="width:100%;height:600px;border:0"></iframe>
The browser session is partitioned by the top-level site. Each origin is exactly a scheme and host with an optional port, such as https://app.example.com:8443. The viewer permits framing by those origins; interactive viewing uses the same allowlist.
Computer use (0.9.0)
A desktop in the workspace for agents that operate GUI software. workspace_set_computer_use with state: "on"
switches it on ("inherit" follows the template); the platform starts the desktop on the first call. The computer
tool takes one action of the Anthropic computer-use action set per call (action plus its parameters: coordinate,
text, scroll_direction, scroll_amount, region, ...): input actions answer with a screenshot taken after them as
MCP image content, screenshot and zoom with the image, cursor_position with the pointer. computer_batch runs up
to 50 of those actions in one call (click a field, type, press Return) and answers with each action's result, a zoom's
image and one screenshot after them. Both take screenshot: false to skip the image, settle_ms (the wait before it,
default 250) and format: "jpeg" with quality for smaller images. Programs started with exec in the background
(e.g. chromium https://example.com &) open on the desktop. workspace_computer_desktop reports the desktop
(action: "status"), starts it at a screen size ("start", width 640-2560, height 480-1600) or stops it
("stop"). workspace_computer_stream returns a link ({url, expires_at, port, interactive}) to watch the desktop
live, or use it with interactive: true; stop: true ends every view. A call while computer use is off carries a hint to switch it on. Processful
workspaces; a pinned file-first workspace does not list these tools.
New in 0.10.0
workspace_computer_stream reuses a link of the same kind with more than 60 seconds left. Set fresh: true to mint a link; stop: true ends the view and clears it. A computer_batch ending in screenshot or zoom returns that image once. SHARDFLUX_BASE_URL aliases SHARDFLUX_API_URL; the latter wins. The SDK transport honors environment HTTP(S)_PROXY and NO_PROXY.
Explicit pixel completion (0.11.0+)
The computer and computer_batch schemas accept pixel_predicate with timeout_ms and 1–16 region/sha256 objects. Unmatched completion is an MCP isError result with no image.
Explicit predicates are enabled when supplied; no environment switch is required. Omitted predicates retain ordinary 250 ms settling.
Require an appended lossless PNG and omit settle_ms. Digests cover row-major RGBA8 bytes including cursor pixels. The exact matched full frame is encoded and returned. A condition already satisfied before input refuses the batch unless allow_pre_satisfied explicitly allows that semantics. Timeout returns no success image; input may already have run, so inspect input results before retrying. Use a known, semantically unambiguous result. A pixel condition cannot certify unpainted backend state or infer completion from focus or quiet.
Exact text entry (0.11.0+)
pasteText replaces the clipboard with UTF-8 text and sends the chosen paste chord. Use shift+Insert for xterm. Ordinary type sends line breaks as Return. Start with all keys released. Clipboard replacement remains in effect after cancellation; see computer use for action results.
The computer tool accepts action: "pasteText", text, and optional paste_chord; computer_batch accepts the same action. Clipboard replacement must be explicit.
Background commands (0.7.0)
exec with background: true starts a long command (a build, a test suite, a training run, a server) and returns
{session_id, state} at once, so the agent keeps using the other tools. exec_read reads its state, exit code and
output: the end of each stream, or from the next_stdout_offset / next_stderr_offset of the previous read, and
wait_ms (up to 60000) waits for the exit and returns as soon as it happens. exec_cancel stops it (SIGTERM, then
SIGKILL after grace_ms, 1-60000, default 5000). With background, timeout_ms is the command's own limit (up to a
day) rather than the call's deadline, and the workspace stays awake while the command runs. A burst
(burst: "always") runs in the foreground. workspace_exec_start (with timeout_ms, 0.7.0)
starts sessions that exec_read and exec_cancel read and stop the same way. Processful workspaces.
Pending execution cancellation (0.20.0+)
On workspaces that advertise exec_cancel_pending.v1, successful cancellation can return the actual running state
with canceled: true while the kernel holds a killed process. The execution's error explains pending drain,
and becomes unverified after 30 seconds without claiming an exit or freeing ownership. Read/follow that
session until its real final status; repeat cancellation is idempotent. An already exited foreground keeps
its result while descendant drain can remain pending. TS/Python agent tools and MCP expose the reason as
status_reason and keep the exit code null while active. CLI prints the reason and follow command.
Other clients read the same session response fields.
Burst execution (0.7.0)
exec takes burst: "always" (with optional burst_vcpus and burst_memory_mib) to run one heavy command, such as a
cold build or a full test suite, on a larger, short-lived burst VM over a copy of the workspace. Output and exit code
are the command's own, and its file changes are applied back when it exits. The result adds burst (size, method,
changes applied, overhead). If applying the changes fails (burst_apply_failed), call exec again with the same
session_id to finish the apply.
Elastic memory (0.7.0)
workspace_open and workspace_fork take allocation_mode (fixed or elastic) and memory_mib_held next to the
caps. An elastic workspace holds only the memory its commands use and grows up to memory_mib when they need more;
billing counts the memory it holds. It idles at memory_mib_held (default 1024). Package installs, test runners,
compilers and bundlers get their memory before they start, so they see what they need from their first instruction;
everything else starts at once and the workspace grows while it runs. fixed gives a static allocation of
memory_mib. exec and workspace_exec_start take resource_hint (0.8.0): heavy gives the command its memory
before it starts, light starts it at once, auto (the default) decides from the command. Workspace results carry
memory ({allocation_mode, promised_mib, held_mib, plugged_mib}), and an exec result carries memory_grow
({outcome, from_mib, want_mib, got_mib, deliver_ms}) when the command's start grew the workspace.
Resize (0.8.0)
workspace_resize changes a workspace's memory, CPU and disk without a restart, running or suspended, fixed or
elastic. Memory changes live and disks grow online; a suspended workspace gets its new size when it resumes, before its
first call. CPU changes live within the vCPUs the workspace booted with; a larger CPU size applies at the next start.
The new caps are stored, so every later start uses them. A typical result:
{ "state": "running",
"memory": { "applies_at": "now", "previous_mib": 2048, "target_mib": 6144, "applied_mib": 6144, "converged": true, ... },
"disk": { "applies_at": "now", "previous_gib": 10, "target_gib": 20, "applied_gib": 20, ... },
"caps": { "memory_mib": 6144, "disk_gib": 20, "cpu_millis": null, "allocation_mode": "fixed" },
"message": "memory 2048 → 6144 MiB now; disk 10 → 20 GiB now." }
Resize controls (0.10.0+): workspace_resize accepts at_least: true to grow only resources that need more
capacity, and wait: false to return the held server answer with its operation. The default waits for completion.
Fixed memory without memory_mib uses the template default.
At its maximum (0.26.2+): a workspace already uses its full CPU and memory from boot and its disk grows on its own as it
fills, up to the plan's and the template's maximum, so a slow build is not a reason to resize. Each resource carries
at_maximum, and the message says plainly when one was already there: cpu is already at its maximum, 32 vCPUs (plan limit): nothing changed; the workspace already runs on all of them, as many as its processes use.
Suspension progress and cancellation (0.19.0+)
workspace_suspend_progress reads the actual phase/deadline and cancellation window; workspace_suspend_cancel
requests cancellation before capture. Both require operation_id and the named workspace, and respect a pinned
workspace. Cancellation waits for confirmed suspend_canceled original-workspace recovery by default; wait:false
returns asynchronous acceptance. A closed preparation window is refused. Neither tool resets or replaces the
workspace. They are absent for pinned file-first workspaces, and unavailable progress stays explicit.
Integration controls (0.6.0+)
workspace_open accepts labels and idle_policy; workspace_list accepts exact label filters. workspace_set_labels replaces all labels. workspace_idle reads activity without waking, workspace_keepalive declares ongoing work, and workspace_set_idle_policy accepts adaptive, never, fixed:, or default.
workspace_exec_start starts a tracked background command with optional stdin_open and (0.7.0+) timeout_ms; read it with exec_read and stop it with exec_cancel; workspace_exec_input writes data at an acknowledged byte offset and can send EOF with close. Both require exec permission and processful workspaces. Frames are bounded to 64 KiB; use the returned offset after partial acknowledgements.
workspace_resume recovers failed IDs without replacing their disks. A completed delete frees the key for a new workspace ID. Protocol errors include their source; a bare 404 is not a workspace tombstone.
Prepare an imminent tool call (0.8.0+)
Set SHARDFLUX_PREWAKE=on to offer workspace_hint (default off). A host that observes model input streaming can call it with the workspace key ahead of a VM tool call. It returns without waiting for restore; the following tool uses the workspace normally. Resume a suspended workspace first. The MCP server receives completed tool arguments, so the host supplies the early signal explicitly. File-first workspaces do not list this tool.
Idle deletion retention (0.10.0+)
Pass retention: {"delete_after_idle_days": 14} to workspace_open to delete a persistent workspace automatically
after 14 idle days. workspace_set_retention takes the same policy and workspace_key; pass retention: null to
follow the project default. Workspace results include effective days and delete_at. Policies accept 1 through 3650
days. Tool calls and ongoing work postpone deletion.
Workspace upgrade (0.10.0+)
workspace_upgrade keeps files, installed package files and home through one cold start. Memory and processes end. Its at argument accepts now or next_resume; the returned operation says whether the upgrade is scheduled or applied. workspace_get includes available and pending targets.
Shared volumes (0.12.0+)
volume_open creates or reuses a project volume by name (optional quota_gib) and waits until it is available unless
wait: false. volume_list lists the project's volumes, optionally with the organization's shared volumes
(include_org_shared); from 0.13.0 each volume carries its kind and measured storage usage. workspace_open takes
volumes (guest mount path to a volume name or {name, mode}, mode ro or rw) and like (a source workspace
ID or key in the project: a fresh disk with the same configuration).
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. Workspace results carry mode and, for file-first workspaces, tree_revision.
exec runs each command as an execution: a fresh VM on the workspace's files. Only files under /home/user persist
between calls. The result adds execution_id, state, tree_revision and changed (the paths the command added,
modified or deleted, up to 200, with changed_truncated). An execution runs to completion: when the call's
deadline passes first, the error carries its execution_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_fork,
workspace_resize and operation_wait do not apply. A pinned server lists only the tools of its workspace's mode: the mode of the
pinned key once it is known, else SHARDFLUX_WORKSPACE_MODE, else processful. When the known mode changes what it
listed (for example the pinned key is opened file-first after the first tools/list), it sends
notifications/tools/list_changed. An unpinned server lists every tool; calling one the named workspace's mode
lacks returns an error with reason: "not_supported_for_mode" and a hint, before any request.
- Errors of file-first workspaces carry
reason and a hint: not_supported_for_mode, mode_mismatch (a key's
mode never changes), mode_not_available (the account does not have file-first workspaces), layout_unsupported
(a template version that is not layered), tree_revision_mismatch (with current_tree_revision),
outside_tree_root, execution_in_progress (another execution holds the workspace), execution_id_reused and
no_execution_host (the execution cannot be placed right now; retried with the same id; nothing ran).
{
"mcpServers": {
"shardflux": {
"command": "npx",
"args": ["-y", "@shardflux/mcp"],
"env": { "SHARDFLUX_API_KEY": "sfk_...", "SHARDFLUX_WORKSPACE_KEY": "me/agent-files", "SHARDFLUX_TEMPLATE": "python-node-browser", "SHARDFLUX_WORKSPACE_MODE": "file_first" }
}
}
}
Immutable paths (0.7.0)
A recipe's immutable list names directories every workspace of the template mounts read-only from the template's
newest published version; workspaces pick up a new version at their next cold boot or resume. template_get shows
each version's immutable ({paths, bytes}, or null), template_build results carry immutable_paths, and workspace
results carry template.immutable_version: the version whose immutable paths the workspace has mounted. A recipe
without immutable keeps the open version's list; each new version keeps every path of it. Writing under an immutable
path returns reason: "read_only_path" with a hint; the build refusals immutable_path_removed,
immutable_paths_unsupported_base and invalid_path (at recipe.immutable[<i>]) carry one too.
Initialized CPU services (0.11.0+)
Template services accept initialized_cpu with compatibility, reset, and timeout_seconds. Use cpu-service-v1 for immutable initialization, or cpu-service-fresh-inputs-v1 with fresh_env_names for values supplied at each open. Declare an unprivileged user and command readiness. Each open runs the reset script and its owned startup hooks before returning. Initialization-dependent and secret inputs use ordinary startup.
Sealed-file reads (0.11.0+)
Additive: read_sealed_files is a read-only processful tool with ordered paths and optional generation. It reads up to eight complete files from a suspended sealed generation, returns exact base64 bytes with revisions and explicit errors, and sends no wake hint. It is excluded from file-first mode.
Use sealed-file reads for complete files from one suspended generation. If the generation changes, request a fresh read. See lifecycle for the read contract.
Git clones
The processful git_clone tool accepts optional filter: "blob:none" (0.11.0+, SDK 0.17.0). Current checkout files are fetched now; historical blobs fetch from origin when needed. Omit it for a complete clone. No shared cache is enabled.
Parallel Git checkout (0.11.0+)
Set parallelism (1–16) to choose Git indexing threads and checkout workers for this clone. The git_clone tool forwards it; CLI callers use git -c pack.threads=4 -c checkout.workers=4 clone ... through shard ws exec.
Treeless Git clones (0.11.0+)
Set filter: "tree:0" (Python: filter="tree:0") to fetch the requested checkout and commit graph now, with historical trees and blobs fetched from origin as needed. CLI callers use git clone --filter=tree:0 through shard ws exec. See Git for clone options.
Explicit browser readiness (0.11.0+)
The browser_screenshot and browser_content tools accept an explicit readiness declaration. Set readiness to describe the visible state needed for this observation. Omit it to wait for the full page load.
A declaration requires 1–32 DOM conditions (selector, exact equals, and
optional property: "text" | "value"). Optional images (up to 32 selectors),
fonts (up to 16 CSS font descriptions and sample text), and focus declare
the state needed by this observation. The helper binds to the new navigation,
checks declared values, decodes images and loads fonts, captures the Chromium
compositor surface, then rejects changed loader or page state. A timeout or
unmet condition fails the request. See browser tools for readiness and timeout behavior.
Decide between known options (0.26.2+)
decide asks the decision model questions whose options your agent already knows, about an input (the context and
the words, as plain text): which project, which file, which kind of request. Each question has a name, its
instructions and 2 to 60 choices (value and a short description); up to 12 are answered together. Each answer is
one of the choices with a confidence from 0 to 1 and every choice's probability; low confidence means ask the person.
cache_seconds reuses the answer for the same input and questions.
{"input": "The person wrote: \"check on our model training\". Their projects: status-board, site.",
"questions": [{"name": "where", "instructions": "Where does what the person means most likely live?",
"choices": [{"value": "status-board", "description": "The status-board project"},
{"value": "site", "description": "The site project"},
{"value": "their_computer", "description": "A folder or job on their own computer"}]}]}
answers {"answers": [{"name": "where", "choice": "their_computer", "confidence": 0.89, "probabilities": […]}], "cached": false, …}. A dependency_unavailable error with reason model_unavailable is retryable: call decide
again after retry_after_seconds. It is listed with the board tools (SHARDFLUX_MCP_TOOLS=all lists every tool).
Feedback: preview and user approval
(0.19.0+) Every local and hosted server uses user-directed feedback. send_feedback with 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. The feedback: 'proactive' option uses the same consent policy.
Agents report only when their 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. Failed calls retain a feedback suggestion with request and error IDs; it asks for a preview and approval.
- Arguments:
message (any length, 0.26.2+; a whole log is fine) and category (bug, confusing, missing, idea, praise, other),
plus optional user_approved (true only after explicit approval), workspace (default: the pinned key), request_id, error_code and command.
- The server adds
client: shardflux-mcp/<version> and, as agent, the MCP client's name and version from
initialize (e.g. acme-agent/2.1.0; without one, SHARDFLUX_AGENT_LABEL when it is not the default mcp).
- Approved submission result:
{id, received_at, duplicate, note}. 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 per key:
rate_limited
with details.retry_after_seconds, and a hint naming the wait and the fallback address, shardflux@shardflux.dev.
Updates (0.4.0+)
At startup, after the configuration is validated, the server asks the API's GET /v1/client-versions whether
@shardflux/mcp at its version is current. It sends one request (3 s timeout) in the background: the MCP handshake
and tool calls never wait for it, 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:
{"time":"2026-10-01T09:00:00.000Z","level":"warn","service":"shardflux-mcp","message":"@shardflux/mcp 0.20.0 is outdated: 0.20.1 is available. Update: npm install -g @shardflux/mcp@latest","status":"outdated","package":"@shardflux/mcp","current":"0.20.0","latest":"0.20.1","minimum_supported":"0.1.0","upgrade_command":"npm install -g @shardflux/mcp@latest","release_notes_url":"https://www.npmjs.com/package/@shardflux/mcp?activeTab=versions"}
- A server below the minimum supported version logs
"status":"unsupported" with the minimum version and the update
command. It keeps running.
- Otherwise it stays silent (one
debug line), also when the API does not answer.
- The server instructions do not carry the notice: they are fixed when the server is built, and the handshake does not
wait for the check.
SHARDFLUX_NO_UPDATE_CHECK=1 or NO_UPDATE_NOTIFIER=1 turns the check off; createShardfluxMcpServer(config, { versionCheck: false }) does too.
- The
@shardflux/sdk client inside the server runs no check of its own (versionCheck: false). The SDK ships inside
the server, so the update to install is the server's.
More details
Template file lists: TypeScript SDK 0.27.0+ / Python 0.23.0+ wait the full Retry-After of a retryable API 409
file_list_indexing on GET/HEAD within the admission timeout, while the list is assembled. Template objects and version
history stay available.
Support and bug reports
Report a bug or
request a feature.
Include the package and runtime versions, a minimal reproduction, expected and actual behavior, and the request ID
or error code when available. Reports are public: leave out secrets and confidential data.
For usage, account, billing, or private support, email shardflux@shardflux.dev.
Report vulnerabilities through private security reporting.
See the support guide for all reporting options.
License
Apache-2.0
Saved site logins (0.26.2+)
Your laptop agent can use site_logins_list to read login metadata and site_login_add to open a secure entry
page. Give the returned URL to your user: the password goes directly from that page to the encrypted store.
The tool returns waiting; list logins after the user saves. Passwords, authenticator seeds and passkey
private keys stay outside tool arguments and results. Sign in with shard auth login, or provide
SHARDFLUX_SESSION_TOKEN in the server environment. The server uses the session saved for its API URL.
The secure entry page is included through @shardflux/cli; a global shard install is unnecessary.
These tools run on your laptop. credential_fill accepts an account username and the passkey field.
Account creation requests (0.27.2+)
needs_you_answer accepts decision: "create_account" after the person chooses it. The requesting agent creates the account and stores generated credentials securely; existing values never pass through tool arguments.
Approval modes and the Everything budget (0.28.0+)
approval_policy_set takes four modes: ask (Ask every time), routine (Routine work), trusted (Project work:
deploys, publishing, pushes to main, spending, infrastructure changes and credentials still come to the person) and
autonomous (Everything: agents sign in with saved logins, create the accounts and keys they need, read login codes,
deploy, and pay within the monthly budget). spend_limit_usd sets that budget in US dollars per calendar month; a
person signed in sets it and the default mode. approval_policy_get returns spend_limit_usd and spent_usd, and
approval_activity lists what agents did on their own, newest first, with next_cursor.
Codex account selection
The manually active Codex account applies across every project in your organization, including running VMs. Change it in Settings → Agents or with shard agents accounts use <account>. MCP account tools list the selection; they do not change it. This is server behavior and also applies to existing supported client versions.