Skip to content

MCP server

Give an AI agent Glac's products as tools, Cubes to deploy and sandboxes to work in, in Claude Code, Claude Desktop, Cursor or any Model Context Protocol client.

Updated View as Markdown

The MCP server lets a model deploy an image as a Cube, or several Cubes together, read their logs and go back to an earlier version; make sandboxes, run commands in them, read and write files, open ports, take snapshots and roll back; make Drives, disks that outlive sandboxes, mount them, keep snapshots of them and back them up; point domains at apps and sandboxes; and look at the project and the account. It keeps no state of its own: everything goes through the TypeScript SDK to the API.

It needs Node 23.6 or later, and runs from npm as glac-mcp, which brings the official MCP TypeScript SDK it is built on:

GLAC_API_URL=https://api.glac.ai GLAC_API_KEY=ak_... npx glac-mcp

Connect a client

Claude Code:

claude mcp add glac -e GLAC_API_URL=https://api.glac.ai -e GLAC_API_KEY=ak_... -- npx glac-mcp

Claude Desktop (claude_desktop_config.json; on macOS in ~/Library/Application Support/Claude/), and Cursor (~/.cursor/mcp.json or .cursor/mcp.json in a project) take the same entry:

{
  "mcpServers": {
    "glac": {
      "command": "npx",
      "args": ["glac-mcp"],
      "env": { "GLAC_API_URL": "https://api.glac.ai", "GLAC_API_KEY": "ak_..." }
    }
  }
}

Over HTTP

glac-mcp serve --http serves the same tools over MCP’s Streamable HTTP transport at /mcp, for a client that connects to an address instead of starting a process:

npx glac-mcp serve --http 127.0.0.1:7071
claude mcp add --transport http glac http://127.0.0.1:7071/mcp --header "Authorization: Bearer ak_..."

The server holds no key of its own: each request brings an API key as a Bearer token, the server checks it with the API (and takes it as good for 30 seconds), and the tools use that key and no other. A request without a key, or with one the API does not know, is answered 401 with a WWW-Authenticate: Bearer challenge that points at the endpoint’s protected resource metadata (RFC 9728, at /.well-known/oauth-protected-resource/mcp); signing in with OAuth is not offered yet. Every request is served on its own, with no session, so any number of these servers can stand behind one address. It listens on this machine only unless told otherwise; on any other address put TLS in front of it, and set GLAC_MCP_PUBLIC_URL to the address clients use.

Tools

The 73 tools follow what a model needs to do, not the REST calls one by one. They are grouped, and named, by product: Cube (cube_*; the same tools answer to worker_* too, which are not listed), Sandbox (sandbox_*), Drive (drive_*), domains (domain_*), Browser (browser_*), Database (database_*), Managed Applications (catalogue_*, installation_*), then the project (project_*) and the account (account_*), and listed in that order.

Cube

Cube runs an image as a service at an address of its own, a Cube, which the API calls an app, and so do the tools’ arguments (app). These seven need the platform’s control plane.

Tool What it does
cube_deploy Deploys an image to the app of a name, which is made the first time; what holds at once (public, regions, the scale, checkpoint_seconds: checkpoints of its keyed instances, 0 for none) is changed first. What holds at once also takes concurrency, depends_on, network (aliases, how it is reached) and metadata. A version also takes volumes (under the server’s prefix), kind, user, working_dir, stop_signal, stop_grace_ms, hostname and runtime (limits, sysctls, tmpfs, its resolver, the size of /dev/shm); never a file, which is how an app would be given a secret. Waits for the version for a while, and says whether it is ready, failed (in the image’s own words) or still building.
cube_list The apps, or one in detail: its versions, where its traffic is, its keyed instances, the secrets its keys are signed with (by their first characters, never a value) and what its log counted. A database’s app says which database (managed_by), which deploys and deletes it: a deploy or a rollback of it here is refused.
cube_rollback Sends an app’s traffic back to an earlier version.
cube_metrics What the machines that serve an app counted of it, minute by minute or hour by hour: requests, those refused and by the class of their status, p50 and p99, instances awake and stopped, wakes, instances made, CPU and memory; the steps with something in them, and what they add up to.
cube_logs Reads an app’s log: what its instances printed, its requests, what the platform did; by instance, version, kind, status or text, and on from a cursor.
cube_instance Makes or deletes the instance of a key. Moving one to another version in place replaces its machine and ends its connections, and so does its revert: that is a person’s to start, cancel and follow (glac cube upgrade, `glac cube upgrades revert
cube_instance_ports The own public IPv6 address of a key’s instance and the ports open at it, wherever the instance is: open opens a port (TCP, or UDP) to the sources from names (IPv6 prefixes or addresses, ::/0 for everybody, which has to be said), close closes one. What is open stays open while the instance sleeps (a packet wakes it) and when it moves; a new instance of the key has none of it. The program has to listen on ::.

Sandbox

Tool What it does
sandbox_run Runs a command and waits. With a sandbox name the sandbox is made the first time and kept; without, a one-off sandbox is used and deleted. A sandbox it makes (as sandbox_exec makes one) takes a service of its own that starts when it boots (start, start_command, ready), project_network, hostname and stop. A sandbox it makes with init: "systemd" is a whole system: the image’s own systemd is PID 1 (without image, the platform’s Ubuntu with systemd and OpenSSH), so packages, services started with systemctl, cron and the journal work as on a machine; sandbox_exec takes it too, and sandbox_list shows each sandbox’s init.
sandbox_exec, sandbox_output, sandbox_stdin, sandbox_signal Starts a long command; reads its output from a position; writes to its input; sends it a signal.
sandbox_read_file, sandbox_write_file, sandbox_list_files Files. Images come back as images; other binary files are only described.
sandbox_url A link to a port.
sandbox_ports The sandbox’s own public IPv6 address, where it has one, and the ports open at it: open opens a port (TCP, or UDP) to the sources from names (IPv6 prefixes or addresses, ::/0 for everybody, which has to be said), close closes one. Inbound is closed by default; what is open stays open while it sleeps (a packet wakes it) and when it moves. The program has to listen on ::.
sandbox_revoke_tokens Revokes every token handed out for a sandbox so far, those in preview links and cookies and those SSH sessions hold too (401 invalid_token from then on); tokens made after it work. With token (the token, or its id), that token alone.
sandbox_egress What a sandbox may reach on the internet: default, allow and deny (default deny with an allow list keeps code you do not trust in), or clear. A sandbox named for the first time is made with the rules. The rules that add a secret to requests or name the requests a host may be sent are the project’s, and are left alone.
sandbox_checkpoint A sandbox’s checkpoints while it runs, shown, and set with every_seconds (1 to 600; 0 turns them off): when its machine is lost, it goes on elsewhere from its last one with its processes. Off by default; a sandbox named for the first time is made with them. Where no machine takes checkpoints it is refused (checkpoints_unavailable).
sandbox_list, sandbox_sleep, sandbox_delete The sandboxes and snapshots, or one in detail (with how its checkpoints go, where it has them); sleep now; delete.
sandbox_snapshot, sandbox_fork, sandbox_restore Snapshot, fork, and back to a snapshot in place.
sandbox_add_ssh_key, sandbox_list_ssh_keys, sandbox_delete_ssh_key An SSH key for one sandbox, for a day unless you say (30 days at most).

Drive

A Drive is a disk of the project’s that outlives the sandboxes that use it: mounted read-write by one sandbox at a time, and kept, with what it holds, for the next sandbox: of its region, or of another whose machines read its home’s object store. A snapshot keeps a Drive as it is at an instant, a version of it in the object store: nothing is copied. A backup is a copy of it at an instant, in the object store, until it expires. These sixteen need the platform’s control plane. Behind a prefix, the server’s Drives carry it, and it mounts them in its own sandboxes only, so a Drive is made with a name.

Tool What it does
drive_create Makes a Drive of a name, a size in GiB (64 unless you say, or 5 on Free) and a region, standard or strict (an fsync in the sandbox that has it returns once the object store holds every write before it; kept for good). Only what is written is billed.
drive_list, drive_get The Drives, or one in detail: size, what is written, region, the sandbox that has it and where, the node that writes it, its home (the region whose object store holds its copy) and how far a move of it is (home_move: a Drive’s home follows it to another region an hour after it got there; no tool moves it sooner, glac drives home does), the Drive a fork was made of, the database a database’s Drive is under (managed_by: its instance alone mounts it read-write, and a rename, a restore or a delete of it is refused).
drive_attach Mounts a Drive in a sandbox at a path, read-write, at once; one another sandbox has is refused, and the result says which has it. With snapshot, one of its snapshots instead, read-only, which any number of sandboxes mount at once.
drive_detach Takes it away again (force while a process still uses it); it keeps what it holds. With snapshot, that snapshot’s read-only mount.
drive_delete Deletes a Drive and what is on it; one that is mounted is not deleted. Its snapshots stay, and the result names them.
drive_snapshot, drive_snapshot_list, drive_snapshot_delete Takes a snapshot of a Drive (fs_consistent freezes the file system of the sandbox that writes it; otherwise its machine is paused for a moment, as at a power cut), lists a Drive’s snapshots (without a Drive, those of every Drive, a deleted one’s among them), deletes one.
drive_fork A new Drive of a name, made of a snapshot or of the Drive as it is now: nothing is copied, and it can be mounted at once.
drive_restore Brings a Drive back to one of its snapshots; one a sandbox has is refused: drive_detach it first.
drive_versions The versions a Drive keeps of itself where its window is set (its history_seconds: one every 30 seconds in which it was written), the newest first; with at, the one a restore or a fork to that time takes.
drive_backup, drive_backup_list, drive_backup_get, drive_backup_delete Takes a backup of a Drive (a sandbox that writes it has its file system frozen for a few milliseconds, so that the copy is at rest), kept until it expires (expires_in_days, or the Drive’s rule: 30 days unless set); lists the backups of the server’s Drives, or of one, newest first, with why each was taken (manual; daily, by the Drive’s rule; before_version, before a service’s new version); shows one; deletes one.
drive_backup_restore A new Drive of a name, made of a ready backup: the size of the Drive it was taken of, in its region, restoring until all of it is back from the object store, then ready (drive_get says which), and mounted by nothing before. Where the machine it is made on cannot bring it back, the platform tries once more on another.

The model calls a snapshot by its name or its id (dsnap-…), always with its Drive: drive_snapshot gives no name twice among a Drive’s snapshots, and behind a prefix it names each one under the prefix, making a name up (the Drive’s and the time) when none is given. A snapshot outlives its Drive: the result of drive_delete names those that remain, and they are reached by the Drive’s id. A snapshot is billed for what it keeps alone, at the Drives’ data price ($0.02 a GB-month), until it is deleted; a fork is billed by all it holds, like any Drive (a fork of a 10 GB snapshot is billed as a 10 GB Drive); what a read-only mount reads from the object store costs nothing. A restore keeps the versions in between where a snapshot or a fork keeps them, so a Drive restored to an older snapshot can be restored to a newer one after; what it held that no snapshot kept is gone.

A backup is not a snapshot: a snapshot is a version of its Drive, while a backup is a copy of its own, called by its id (bak-…), with no name, from which a Drive is made alone. A Drive’s backups keep only what changed since the one before, and a block several of them need is billed once, on the earliest: what each is billed for (stored_bytes), what deleting it would save (own_bytes) and what it shares (shared_bytes) are in its row. It is making until the object store has all of it, then ready, and billed from then at the price of what sleeping sandboxes keep ($0.02 a GB-month), until it expires or is deleted. It outlives its Drive: a new Drive is made of it whatever became of the one it was taken of. Behind a prefix, the server sees the backups of its own Drives alone, and names a Drive made of one under the prefix. A Drive whose machine copies nothing to an object store has none: drive_backup says so.

Domains

Tool What it does
domain_create Registers a name of the user’s own for an app of the server’s, or for a port of one of its sandboxes; it is pending_verification until DNS shows the record the result names (a CNAME, which also leads the name here, or a TXT record), and then its certificate is issued. The user adds the record at their DNS provider.
domain_list, domain_update, domain_delete The domains that lead to the server’s apps and sandboxes, with the records that prove each while it is not proven; one pointed at another app, sandbox or port; one deleted.

Browser

Not open yet. Browser is not open to accounts yet: what follows is the server as it stands, ahead of its opening.

A session is a hosted Chromium, awake while a client of the Chrome DevTools Protocol (CDP) is connected to it and asleep, its pages kept, a few seconds after the last one leaves. The server opens and closes sessions; what is done in the browser is done by Playwright’s MCP server, connected at the session’s address (npx @playwright/mcp --cdp-endpoint <cdp_url>). These three need the platform’s control plane. Behind a prefix, the server’s sessions carry it in their names: it sees and closes its own alone.

Tool What it does
browser_open Opens a session (headless unless headful), or the one of the name given, woken, with its pages, and gives its CDP address (cdp_url) and where a person watches its page live (live_url). The address is the credential: whoever has it drives the browser.
browser_list The server’s sessions: name, kind, whether each is awake (or failed, with why: its browser stopped and did not come back) and how many clients are connected. No address.
browser_close Ends a session for good: its browser, its pages and its connections.

A session is billed by the Cube resources it uses, as any instance is: its CPU while it computes, its memory while it is awake and its traffic out (pricing and plans). account_usage gives a session’s use beside its sandbox.

Databases

A database is a managed Postgres, asleep when nothing asks anything of it and woken by a connection, its sessions kept. The server makes them and branches of them, and looks at them; deleting one or a branch, putting it to sleep, waking it and a new password are a person’s (glac db rm, glac db branches rm, glac db sleep, glac db wake, glac db reset-password). These four need the platform’s control plane. Behind a prefix, the server’s databases carry it in their names: it sees its own alone.

Tool What it does
database_create Makes a database (PostgreSQL 18 unless version), ready in a few seconds, and gives its connection string with the owner’s password: the one time it is given, so the model keeps it where the program that connects needs it (an environment variable such as DATABASE_URL). The name of one there is gives that one, without its password. On a Free plan sleep_after_seconds is 1, fixed.
database_list The server’s databases: name, version, status, whether each is awake, paused or asleep, and its connection string without the password.
database_get One database and its branches (main, then those made of it), each with its endpoint, its state and its connection string without the password; with branch, that branch alone. It says the database’s rest (how long it is held paused before it sleeps, its daily wake), from when its root branch can be restored, and the gaps of its WAL archive (where the object store refused its WAL so long that it was given up; a time in one is restored only to a whole minute, from its Drive’s window): a restore is a person’s (glac db restore).
database_branch_create A branch of a database: a copy of main (or of parent) as it is now, made at once whatever its size, with a PostgreSQL of its own, to try a migration or a change on the real data without touching it. It gives the branch’s connection string without the password: its roles and passwords are its parent’s, so the owner logs in with the password database_create gave. With expires_in_hours it is deleted by itself then; otherwise a person deletes it (glac db branches rm).

A database’s history (how far back it can be restored, glac db update --history) and a restore of it in place (glac db restore: its root branch back to a time, its connections dropped, its state before kept as a branch) are a person’s: no tool does either. A Drive’s window of versions is in the SDKs and glac drives versions|history, not yet among these tools.

A database is reached on the project’s network, from a sandbox made with project_network: true (and from the project’s apps), at its name.

Managed Applications

An application of the catalogue (Rivet, say) is installed in the project as its own Cube resources, labelled with the installation and changed through it alone (Managed Applications). The server looks at the catalogue, installs, and looks at the installations; changing one and deleting one, which takes its Volumes and buckets with what they hold, are a person’s (glac installations update, glac installations rm). These five need the platform’s control plane. Behind a prefix, the server’s installations carry it in their names: it sees its own alone.

Tool What it does
catalogue_list The catalogue’s applications, each with what it is, its licence, whether the platform packaged it, and what a month of it comes to in Cube’s meters.
catalogue_get One application (app, version): the parameters an installation of it takes (a JSON Schema), its outputs, and its month in Cube’s meters.
installation_create Installs it (app, name, version, region, parameters, requires), waits for it up to the server’s wait, and gives its outputs, the secret ones too, which the model keeps where the program that uses it needs them.
installation_list The server’s installations: application, version, status, region, what each is made of and its outputs.
installation_get One installation: its status (and why, where it failed), its apps, Volumes and buckets, and its outputs (a secret one hidden where the server’s key may not manage the project).

The project and the account

Tool What it does
project_get, project_set_variable The project and its events, each in a few words (among them a Browsers session that failed after it had run; a database made, deleted, branched or restored, its WAL archive failing and archiving again, and a gap in it, opened and closed; and of the others, what each is of), and its shared variables, which an app’s env refers to: a control plane’s. project_get also shows the project’s spend limit and what it spent this month, its webhooks, its API keys and where the logs of its apps are exported (never a secret, a key or a header’s value; webhooks and keys with a key that has the admin scope), which a person sets up: no tool makes or changes them. Asking for one of the account’s limits to be raised is a person’s too (glac limits request).
project_secrets The project’s secrets: names and hosts only, never values.
project_deploy Deploys several of the server’s apps together, as one deploy of the project (/v1/deploys): each is given what cube_deploy takes of a version ({}: as it is), and they are taken in the order of what each waits for and switched together. Waits for the deploy a while, and says each app’s version and how it stands, or which app it failed at and why. A control plane’s.
project_deploys The newest deploys of the server’s apps; or one, with each app’s version, how long each step took and why it failed if it did (wait: once it is over). A control plane’s.
project_audit A page of the project’s audit log, the newest first: every call that was no reading, a refused one too, with when, who (a key by its name, a sandbox’s token, a user of the console, the platform, an operator), the method, the path, the status and where it came from; and every reading of an app’s log by an operator. Takes a key with the admin scope. A control plane’s.
account_billing, account_usage The plan, the bill and the usage: read only. The bill also has what the key’s project keeps of volumes and Drives by the numbers a create is held to (keeps; a person asks for more), the account’s billing address and tax id, and says whether a purchase of the account needs the buyer’s express request to have it at once (a consumer’s in the EEA or the UK, who may withdraw within 14 days), in the request’s words.
account_statement A month’s statement (period, YYYY-MM; this month’s unless given): each meter’s line, what it comes to at the list prices, what the credit of the plan’s periods paid, what is left to pay, the parts of the month, the fees, the Credits debited and written off, what the account held at the month’s end, what each project used, and each database’s own line (what it used comes to at the list prices, its history and its tiered data apart). Read only.
account_documents The invoices at Stripe (with the PDF’s link, and of a charge given back, its credit note), the mail the account was sent, and what it may still withdraw from as a consumer in the EEA or the UK, and the withdrawals it made. Read only: a withdrawal is the buyer’s own statement, never an agent’s (glac billing withdraw).
account_settings Where the account’s notices go, the language they are written in, and its own cap on what it sends to the internet in a month: shown, and changed when the person you work for asks. It says when the address is not verified yet (email_verified: no notice goes to it until the link mailed to it is opened) and when mail to it bounced (email_undeliverable: none goes to it until the address is set again).

A few rules the server keeps:

  • State follows the name. A sandbox the model names stays the model’s, with its files, packages and processes, across conversations.
  • A failed command is a result, not an error: a non-zero exit code, a time-out or a signal comes back as a normal result with the exit code on its first line. A missing sandbox, an API that cannot be reached or wrong arguments are errors, with what to do.
  • Long output is cut in the middle: at most 16,384 bytes a call, the start and the end, with the call that reads the rest.
  • A call waits at most 45 seconds; a command still running comes back as running with its id, and sandbox_output waits on.
  • Paying is a person’s job. There are no tools to top up, change the plan, turn on auto reload, withdraw from a purchase or store a secret; the results say which glac command does it. Where the account buys as a consumer in the EEA or the UK, a purchase needs the buyer’s own express request to have it at once: that request is theirs to give (--start-now on the glac billing commands, or the box on the console’s billing page), never an agent’s, and the commands the results name carry --start-now there.
  • Secrets stay out of reach of the model: an app deployed here (cube_deploy, project_deploy) gets no secrets or files from this server, its env refers to shared variables alone, and an image pull secret goes only to the registry configured for it (GLAC_MCP_IMAGE_PULL_SECRETS=GHCR=ghcr.io,HUB=docker.io).

Settings

Variable What it sets Unless you say
GLAC_API_URL, GLAC_API_KEY The API’s address and key https://api.glac.ai; no key
GLAC_MCP_IMAGE The image of the sandboxes it makes The platform’s default image
GLAC_MCP_IMAGE_PULL_SECRETS Pull secrets the model may name, each with its one registry None: public images only
GLAC_MCP_PREFIX A prefix for the names of everything it makes (sandboxes, snapshots, Drives, apps); it sees only those None
GLAC_MCP_WAIT_SECONDS How long a call waits for a command 45
GLAC_MCP_OUTPUT_BYTES How much output or file a call returns 16384
GLAC_SSH_GATEWAY The SSH gateway, for the ssh command lines it writes None
GLAC_MCP_LOG 1 logs every tool call on stderr (over HTTP, every request too) Off
GLAC_MCP_HTTP_ORIGINS Over HTTP: the hosts of web pages a browser may call it from, besides this machine None
GLAC_MCP_PUBLIC_URL Over HTTP: its address as clients reach it, named in its protected resource metadata http://<listen address>/mcp

It is built on the official MCP TypeScript SDK, and speaks the protocol of 2026-07-28 and, for older clients, the initialize handshake of 2025-11-25, 2025-06-18, 2025-03-26 and 2024-11-05: one revision a connection, the one its client opens it with. Not there yet: tools for volumes (the disks underneath Drives), a terminal (pty), a sandbox’s own environment, making a sandbox from a snapshot, and signing in with OAuth over HTTP.

Navigation

Type to search…

↑↓ navigate↵ selectEsc close