DOCSMCP servers
DOCS

MCP servers

isolance runs your MCP server in a sandbox and serves it at an authenticated endpoint, https://mcp.caa.sh/<server-id>. MCP clients connect with a client token. For each request, the gateway checks the token and the tools it may call, records a trace, and passes the request to your server. The server stops when it's idle and starts again on the next request.

A server serves MCP over Streamable HTTP on a port of its sandbox. It can run:

  • A command on the Default image (Alpine Linux with bash, coreutils, Node and Docker).

  • Your own image from registry.caas.sh, with its own entrypoint or a command you give.

The server's sandbox is an ordinary sandbox of your workspace: you manage its size, outbound hosts, labels, files and snapshots like any other (see Sandboxes), and it carries the label caas.sh/mcp-server with the server's ID, which a connector's Reaches can name to give the server an API key without it ever holding the key. You can also add a server to a sandbox you already have.

Sandboxes run on a prepaid balance, so add funds before you deploy.

Deploy from the console

  1. Open MCP servers and choose Deploy server.

  2. Under 1. Choose an image, choose Default or Your image.

    With Default, enter the server's Command, which serves MCP over HTTP on the port you give below.

    With Your image, enter the image's digest reference, registry.caas.sh/<tenant-id>/my-server@sha256:…, with the digest that docker push prints. Command is optional. It replaces the image's entrypoint and command.

    Enter the Port the server listens on for MCP over HTTP.

  3. Under 2. Configure, you can enter a Name: 1 to 63 lowercase letters, digits and hyphens, unique among the workspace's servers. Its sandbox gets the same name when it's free (see Names). Without one, the server is named mcp- and 12 hex digits. Choose a Size. The default is M (1/2 vCPU, 4 GiB of memory, 8 GB of disk), and a server on your own image needs M or larger.

  4. In Allowed outbound hosts, list the hosts the server calls, one per line, or * for every host. Everything else is blocked, and an empty list reaches no host.

  5. Leave Keep state between restarts checked to keep /workspace between restarts.

  6. Choose Deploy server.

The server's page opens with its Initial client token. Copy it now, because it isn't shown again. This token can call every tool and never expires. To give each client its own token, see Client tokens.

Deploy with the CLI

First set up the caas CLI with an API key, as The CLI describes. caas mcp create creates a server in a new sandbox of its own.

Your own image

Push the image to your workspace's namespace of registry.caas.sh first, as Images and the registry describes. --image takes a name with a tag or a digest, or default for the Default image. The CLI resolves a tag to its digest and deploys that digest.

Give the port the server listens on with --http. The gateway sends requests to the path /mcp on that port, or to --path.

shell
caas mcp create --image server:1.2.3 --http 3000 --command "node http.js"

Without --egress, the server's sandbox reaches every host. To allow only the hosts it calls, pass --egress once per host.

The port must be from 1024 to 65535; it needn't be one of the sandbox's ports, which the gateway doesn't use. Listing it with --port as well also gives it its provider's own URL, where the provider's access control applies and client tokens don't guard it. --command replaces the image's entrypoint and command. Without it, the server runs the image's own entrypoint and command. A server on your own image needs size M or larger.

In a sandbox you already have

--sandbox adds a server to an existing sandbox of the workspace, by its ID or name, which runs it itself:

shell
caas mcp create --sandbox web --http 3000 --path /mcp --name web-tools

The sandbox keeps its own configuration, so the sandbox options below don't apply. A sandbox hosts at most one server. Deleting such a server leaves the sandbox.

Options

--name NAME names the server: 1 to 63 lowercase letters, digits and hyphens, unique among the workspace's servers. A new sandbox takes the sandbox options of caas sandboxes create (see Fields), such as:

OptionWhat it does
--size SIZExs, s, m (the default), l, xl, 2xl, or custom with --vcpu, --memory and --disk.
--egress HOSTA host the server may reach. Repeat it for each host.
--env NAME=VALUEA variable for the server.
--idle-stop MINUTESStop after this many minutes without activity, from 5 to 240. The default is 15.
--no-volumesKeep nothing in /workspace between restarts.

The CLI prints the endpoint, the sandbox the server runs in, and the secret of each token it minted: Initial client, unless a server file declares its own. This is the only time a secret is shown.

From a server file

One YAML or JSON file can declare a whole server, client tokens included:

yaml
server: search-mcp
source:
  image: search-mcp:1
  port: 8080
size: m
state:
  persistent: true
idle: stop after 30m
tokens:
  - name: laptop-claude
    tools: [search.query, search.fetch]
  - name: ci-pipeline
    tools: [search.query]
    expires: 30d
egress: [api.search.example.com]
shell
caas mcp create -f search-mcp.yaml
FieldValue
serverRequired. The server's name, unique in the workspace.
sourceimage: IMAGE, an optional command, and the port the server serves MCP over HTTP on.
sizeA size name, xs to 2xl, or "<vCPU> vCPU · <GiB> GiB · <GB> GB". isolance rounds a written size up to one it can run, and the CLI prints a note when it does.
statepersistent: true (the default) or false.
idleHow long the server runs idle before it stops, such as stop after 30m or stop after 2h: 5 minutes to 4 hours.
tokensUp to 20 client tokens. Each has a name, optional tools (every tool when left out) and an optional expires from 1d to 365d (never when left out).
egressThe hosts the server may reach: ["*"] for every host, [] for none. Without it, the server reaches every host.

A file that starts with { is read as JSON with the same fields. The YAML can't use tabs, anchors, block scalars or more than one document.

The CLI checks the whole file before it sends anything. Then it creates the server and its tokens in one request, and prints the endpoint and each token's secret, once. You can add sandbox options the file doesn't declare, such as --label and --env.

In the console, Deploy from a server file on the Deploy a server page takes the same file, pasted or chosen. There, an image must be a digest reference; deploy a file that names a tag with the CLI, which pins it.

Connect a client

You can find the endpoint URL under Endpoint on the server's page, in the CLI's output (caas mcp get <server>), and as url in the API's view of the server. The ID in it is opaque: it doesn't reveal your workspace.

Clients connect over Streamable HTTP and send a client token as a bearer token:

Authorization: Bearer cmcp_…

The server's page shows a configuration to add to an MCP client:

json
{
  "mcpServers": {
    "search-mcp": {
      "url": "https://mcp.caa.sh/<server-id>",
      "headers": { "Authorization": "Bearer $CAAS_MCP_TOKEN" }
    }
  }
}

Put the client token in place of $CAAS_MCP_TOKEN, unless your client fills in environment variables there. In Claude Code, for example:

shell
claude mcp add --transport http search-mcp https://mcp.caa.sh/<server-id> --header "Authorization: Bearer <client-token>"

To check the endpoint from a terminal, send an initialize request:

shell
curl -i https://mcp.caa.sh/<server-id> \
  -H "Authorization: Bearer $CAAS_MCP_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"curl","version":"1.0"}}}'

If the server is stopped, the first request starts it and can take a while, as Idle stop and wake explains.

The gateway applies these limits:

  • A request body can be up to 4 MiB.

  • Each endpoint takes about 1,200 requests a minute. Beyond that, the gateway answers 429.

  • The gateway waits up to 100 seconds for your server to start answering a request. After that, the client gets 504.

  • A request that sends an Origin header other than https://mcp.caa.sh gets 403, so a web page on another site can't call the endpoint from a browser. MCP clients that aren't browsers send no Origin.

Client tokens

A client token gives access to one server's endpoint and nothing else. Its secret starts with cmcp_ and is shown only once, when the token is created. isolance stores only a hash of it.

  • A deploy from the console's form, or with --image or --sandbox, creates one token, Initial client. It can call every tool and never expires.

  • A deploy from a server file creates the tokens its tokens list declares instead, or Initial client if the list is empty or missing.

Give each client its own token. Each client's calls then show under its name, and you can revoke one client's token without affecting the others.

To create a token in the console:

  1. On the server's page, under Client tokens, choose New token.

  2. Enter a Client name. Under Allowed tools, list the tools it may call, one per line, or leave it empty to allow every tool.

  3. Choose Create token, and copy the token. It expires in 90 days.

With the CLI:

shell
caas mcp tokens create search-mcp --name "Claude Desktop"
caas mcp tokens create search-mcp --name ci-pipeline --expires-days 30 --allow-tool search.query
caas mcp tokens list search-mcp
caas mcp tokens revoke search-mcp <token-id>

Each command takes the server's name or ID. --expires-days takes 1 to 365, and the default is 90. tokens list shows each token's ID, name, state (active, expired or revoked), allowed tools, and counts of its calls and errors. On the server's page, the Client tokens list shows when each token was created and last used, and how many requests it made.

Revoking a token takes effect at once: its next request gets 401. It doesn't stop the server or affect other tokens. To revoke a token in the console, choose Revoke beside it.

A server can have up to 20 tokens in force at once. Revoked tokens stay listed for 30 days.

With the API, a token can expire up to a year ahead, or never:

shell
curl https://api.caas.sh/v1/mcp-servers/search-mcp/tokens \
  -H "Authorization: Bearer <api-key>" \
  -H "Content-Type: application/json" \
  -d '{"label": "ci-pipeline", "allowedTools": ["search.query"]}'

The answer is the token with its secret. expiresAt takes a time in milliseconds since the Unix epoch, from a minute to a year ahead. Without it, the token never expires. A GET to the same path lists the tokens, and DELETE …/tokens/<token-id> revokes one.

Tool grants

A token can be limited to the tools you name: up to 32 exact, case-sensitive tool names. A limited token:

  • Can call only those tools with tools/call. A call to any other tool gets 403, and its trace reads Tool not granted.

  • Sees only those tools in tools/list.

  • Can still use resources, prompts and the other methods that aren't tool calls.

  • Can't use the tasks/ methods.

A token without a list can call every tool. In a server file or the API, an empty list allows no tool calls. The gateway checks a grant before a request reaches your server or wakes it. This works the same for every kind of server, your own image included.

You can't change a token's grant. Instead, create a token with the grant you want, then revoke the old one.

Traces and health

On a server's page, Request traces lists its newest requests. Each one shows:

  • the time

  • the tool called, or the MCP method

  • the caller: the name of the client token

  • the duration, highlighted at 1 second or more

  • the result: OK, Error with the HTTP status, Tool not granted, Timed out, or Blocked at gateway

Blocked at gateway is a request refused for its token: it had no token, an invalid one, or an expired or revoked one. Its caller reads no token or invalid token, or names the expired or revoked token. During a burst of refused requests, only a sample of them is traced, but the blocked count includes them all. Traces record the names of methods and tools, never their arguments or results. caas mcp traces <server> prints the newest 100, and caas mcp stats <server> the last 24 hours.

MCP servers shows the last 24 hours across all your servers: requests, requests blocked at the gateway, and the cost of the gateway requests. For each server it shows requests, median latency, and the share of requests that failed with a 5xx status.

A running server's status is Healthy, or Slow while its latency is up. A server is slow when both of these hold:

  • Its median latency over the last hour is at least twice the median of the day before, and at least 500 ms.

  • The last hour and the day before each had at least 20 requests.

The server's page then names the tool, or the method, with the most slow calls.

For what the server process itself prints, see Runtime output on its page, or run caas sandboxes logs <sandbox> with its sandbox's name.

Idle stop and wake

By default, a server's sandbox stops after 15 minutes without activity. You can set from 5 minutes to 4 hours, with --idle-stop, the server file's idle, or caas sandboxes update <sandbox> --idle-stop. Each request that passes the gateway's checks and reaches your server resets the timer. A response that's still streaming keeps the server running until the response ends. While the server is stopped, it bills no vCPU, memory or disk, only the storage of its snapshots.

The next message a client sends starts the server again:

  • The request waits up to a minute for the sandbox to start. If it's still starting after that, the client gets 503 with Retry-After: 5, and should retry.

  • Requests refused for their token never start the server, and neither do calls to tools the token isn't granted.

  • If the server's process exits, the next request starts it again. A server process runs for a day at most, and the next request after that starts it again too.

  • After a failed start, requests get 503 with Retry-After for 1 minute, or for 4 minutes after a second failure in a row. After three failed starts in a row, they get 409 until you start the server yourself.

A stopped server doesn't keep processes or sessions. If you kept state, /workspace is restored, but clients start new MCP sessions.

If you stop a server yourself, requests don't start it again. They get 409 until you start it. You can stop, start or delete a server from its row's menu in MCP servers. With the CLI, stop and start its sandbox, and delete the server:

shell
caas sandboxes stop search-mcp
caas sandboxes start search-mcp
caas mcp delete search-mcp
caas mcp delete search-mcp --keep-sandbox

Deleting a server ends its endpoint and tokens, and deletes the sandbox its create made, unless --keep-sandbox. A server added to an existing sandbox always leaves the sandbox. Deleting the sandbox deletes its server.

Servers also stop when the workspace's balance reaches $0, and stay stopped until funds arrive. See Billing and usage.

Outbound access

A server reaches only the hosts its sandbox's outbound hosts allow. You set them when you deploy, and you can change them later with Edit on the server page's Outbound policy card, which opens its sandbox's network page. While a fresh workspace sets up, cloning a repository and installing package.json dependencies, the server can also reach the repository's host and registry.npmjs.org. A command that runs npx needs registry.npmjs.org among the hosts itself. To call an API that needs a key, don't put the key in the server. Instead, add the API as a connector whose Reaches picks the server's sandbox (caas.sh/mcp-server=<server ID>, or a label of your own), and isolance adds the key to the server's outbound requests.

isolance's own servers in your sandboxes

The AI tools in your sandboxes can also call MCP servers you don't deploy: each connector's that has one, such as GitHub's or Linear's (see What a sandbox sees), and isolance's own, browser for the Browser connector, whose tools drive a web browser signed in with the sandbox's user's logins. They take no client token: isolance adds the sandbox's access to each on its way out, so nothing in the sandbox holds a key, and they serve only your sandboxes, never clients elsewhere.

Change a server

caas mcp update renames a server, or changes the port and path it serves on.

shell
caas mcp update search-mcp --name search
caas mcp update web-tools --http 3001 --path /rpc

A server's port and path apply at the next request. A server's sandbox can't change. With the API, PATCH /v1/mcp-servers/<server> with { "name" } or { "transport" }.

Use the API

Every path below is under https://api.caas.sh/v1, with an API key as Authorization: Bearer <api-key>. <server> is a server's ID or name.

RequestDoes
POST /mcp-serversCreates a server: { "name", "sandbox" or "sandboxId", "transport", "tokens" }. Send an Idempotency-Key.
GET /mcp-serversLists servers, newest first, with nextCursor
GET /mcp-servers/<server>Reads one: its url, sandbox, transport, state and stats
PATCH /mcp-servers/<server>Renames it or changes its transport
DELETE /mcp-servers/<server>Deletes it, and its own sandbox unless ?keepSandbox=true
GET, POST /mcp-servers/<server>/tokensLists or mints client tokens
DELETE /mcp-servers/<server>/tokens/<token-id>Revokes a token
GET /mcp-servers/<server>/tracesThe newest 100 request traces
GET /mcp-servers/<server>/statsThe gateway's last 24 hours

sandbox is a new sandbox's create, exactly as POST /v1/sandboxes takes it. transport is { "http": { "port": 3000, "path": "/mcp" } }, the port the sandbox's server listens on and the path the gateway sends requests to (/mcp by default).

shell
curl https://api.caas.sh/v1/mcp-servers \
  -H "Authorization: Bearer $CAAS_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{ "name": "search-mcp", "sandbox": { "image": "registry.caas.sh/<tenant-id>/search-mcp@sha256:…", "egress": ["api.search.example.com"] },
        "transport": { "http": { "port": 8080 } } }'

The answer, 201, is the server with tokens, each minted token with its secret, once. A repeat with the same key answers the server without its tokens.

Pricing

The MCP Gateway bills per request. That price includes the endpoint, authentication, routing, persistence and observability. A request with a valid client token counts whatever its result, including a tool call the grant denied. Requests the gateway refuses for their token, their size or the rate limit are free.

The server's sandbox bills like any sandbox. On Native:

MeterPriceWhen
CPUOn the pricing pageWhile the server runs, whether it's busy or waiting
MemoryOn the pricing pageWhile the server runs
DiskOn the pricing pageWhile the server runs
EgressOn the pricing pageOutbound data, including the responses your server sends to clients
Snapshot storageOn the pricing pageFor each snapshot you keep

A server that stops when idle pays nothing for CPU, memory and disk while it's stopped. On your own Daytona, Freestyle, Maritime or E2B account, that provider bills the server's compute and egress instead, and the gateway's requests still bill here.

See pricing for every rate, and Billing and usage for how usage draws down the balance.