MCP gateway
Docker Sandboxes includes an MCP gateway for connecting agents to Model Context
Protocol servers. The gateway gives the agent inside the sandbox one MCP
endpoint, while sbx manages the registered servers, OAuth credentials, and
sandbox lifecycle on the host.
This is different from configuring an MCP server directly in an agent such as Claude Code. Direct MCP setup configures that agent's own MCP client. With Docker Sandboxes, you register MCP servers once on the host, and the sandbox gateway exposes them to supported agents inside isolated sandboxes. That host-managed gateway provides a single path for credentials, explicit server loading, live updates, and organization governance.
NoteThe Docker Sandboxes MCP gateway is separate from the Docker Desktop MCP Toolkit. You don't need the Docker Desktop MCP Toolkit to use
sbx mcp, and MCP Toolkit server settings aren't shared with Docker Sandboxes.
Prerequisites
- Sign in with
sbx login. - Use an agent integration that configures MCP at startup: Claude Code, Codex, Devin, Gemini, Kiro, or OpenCode.
- For remote servers that require OAuth without Dynamic Client Registration, register an OAuth client with the server provider.
- For
--local --urlregistrations that resolve to OCI packages, use a host with Docker installed and running. Docker is also required for explicit--command docker ...registrations.
Quick start
Start by registering one MCP server on the host:
$ sbx mcp add notion --url https://mcp.notion.com/mcp
If the server requires OAuth, sbx opens an authorization flow before it stores
the registration. After registration, verify that the server is registered:
$ sbx mcp ls
NAME TYPE URL/COMMAND
notion remote https://mcp.notion.com/mcp
Then start a sandbox and expose the registered server:
$ sbx run claude --name mcp-demo --static-mcp notion
The sandbox starts with an MCP gateway and pre-loads the notion server. The
registration remains on the host and can be reused by other sandboxes.
Register an MCP server
sbx mcp add registers an MCP server by name. The registration records the
server definition on the host. It doesn't attach the server to a sandbox by
itself. To expose a registered server to a sandbox, pass it with
--static-mcp when you create the
sandbox, or use sbx mcp load for a
sandbox that's already running.
Server names can contain letters, numbers, dots, hyphens, and underscores.
The --url flag can point to different kinds of input. The execution location
depends on what you register:
- A remote endpoint URL identifies a running MCP server. The server runs remotely, and the sandbox gateway connects to it.
- A metadata URL with
--localreturns a registry entry,server.json, orserver.yamlthat describes an OCI-packaged stdio server.sbxresolves the image and runs it on the host with Docker. - An explicit command runs on the host as a stdio MCP server.
Local stdio servers run on the host, not inside the sandbox. The agent inside the sandbox connects only to the MCP gateway.
If a --url hostname resolves to a private, loopback, link-local, or cloud
metadata address, sbx registers the server but warns you about the resolved
address. Register only URLs you trust. Fetching a manifest from an untrusted
URL can expose internal services or cloud metadata, and DNS rebinding can
redirect a hostname after it has been checked. OAuth metadata discovery also
blocks private and other disallowed addresses, including redirect destinations.
For a trusted internal server, pass --skip-ssrf-check to skip both the MCP
URL check and the OAuth metadata discovery checks. This permits private OAuth
metadata endpoints and redirects. Use the flag only when you trust the MCP
host, OAuth provider, and all metadata redirect destinations.
Remote endpoint URL
For a remote MCP endpoint, pass the server URL:
$ sbx mcp add notion --url https://mcp.notion.com/mcp
$ sbx mcp add linear --url https://mcp.linear.app/mcp
Custom request headers
Use --header 'Name: value' to send custom HTTP headers to a remote MCP
endpoint, for example to authenticate with an API key. Repeat the flag for
each header, using each header name once:
$ sbx mcp add acme --url https://mcp.acme.com/mcp \
--header 'Authorization: Bearer ${api-key}' \
--header 'Accept: application/json, text/event-stream'
$ sbx secret set mcp:acme:api-key
Replace the example URL with your MCP endpoint. The sbx secret set command
prompts for the API key and stores it in the
host credential store.
The ${api-key} placeholder stays in the registration. When a sandbox
connects, the gateway reads the secret and substitutes its value in the header.
Use single quotes around header values so your shell preserves placeholders.
Placeholders name stored secrets, not environment variables: ${api-key}
reads mcp:acme:api-key, regardless of your shell environment.
Store each placeholder with sbx secret set mcp:<server>:<placeholder>.
Credential headers such as Authorization must use a secret placeholder.
An explicit Authorization header takes precedence over an OAuth access token.
After storing the secret, expose the server to a sandbox:
$ sbx run claude --name acme-demo --static-mcp acme
Custom headers require a remote HTTP endpoint and can't be used with
--command or --local. They also require the host to connect to the server.
The hosted gateway rejects these registrations unless you supply
--oauth-authorization-server, which routes the connection through the host.
Manage header secrets
Header secrets use the global scope on the host. Set them with
sbx secret set mcp:<server>:<placeholder> without --sandbox.
Header secrets require a stored value and don't support --ref or --command
dynamic sources.
To check the header templates and whether their secrets are set, run
sbx mcp inspect acme. The command doesn't display resolved secret values.
The secret store also contains an automatically managed :endpoint record,
such as mcp:acme:api-key:endpoint. This metadata binds the secret to the
registered server's URLs so the gateway can detect an endpoint change before
sending the secret. You don't need to set this record yourself. If you change
the server's endpoint, follow the CLI guidance to set the secret again for
that endpoint.
To rotate a header secret, run sbx secret set with the same name. After
setting, changing, or removing a header secret, stop and restart the sandbox
or restart sandboxd to apply the change to an existing gateway. An existing
connection keeps its previous value, and a server skipped because its secret
was missing isn't retried automatically.
Removing a registration with sbx mcp rm keeps its header secrets and prints
commands to remove them. To remove the example secret:
$ sbx secret rm mcp:acme:api-key
Local stdio server
Some MCP servers communicate over stdio instead of exposing a remote HTTP
endpoint. Use a local stdio server when sbx should launch the MCP server on
the host. You can provide a metadata URL or an explicit command.
From registry or manifest metadata
Use --local --url when you have an MCP community registry URL or a URL that
returns a server.json or server.yaml document. The registry entry or
manifest must describe an OCI package that uses stdio transport. sbx doesn't
launch non-OCI package types, such as npm, from metadata. To use those
servers, register an explicit command.
This path resolves the image from the metadata and starts it on the host with Docker, so Docker must be installed and running on the host.
$ sbx mcp add fetch --local \
--url https://registry.modelcontextprotocol.io/v0/servers/fetch-mcp/versions/latest
If the entry doesn't publish an OCI stdio package, sbx rejects the
registration instead of starting it locally.
A server manifest describes the MCP server package and how to start it. It can be hosted on a GitHub raw URL, internal HTTP server, or CDN.
$ sbx mcp add opine --local --url https://example.com/mcp/opine/server.yaml
From an explicit command
Use --command when you already know the executable and arguments, or when you
need custom Docker flags. The command can be a package runner such as npx or
a Docker container command:
$ sbx mcp add playwright --command npx --args @playwright/mcp@latest
$ sbx mcp add local-image-server --command docker \
--args "run,-i,--rm,your/image"
To set the working directory for the host process, pass --dir. This flag is
only valid with --command:
$ sbx mcp add local-fs --command node --args server.js --dir /srv/data
Use registry or manifest metadata when you have a published server definition
and don't need to customize docker run. Use --command for local
development, private servers, or custom container flags.
WarningLocal stdio servers run on the host, outside sandbox isolation. If the command starts a Docker container, that container uses host Docker isolation, not sandbox isolation. The process or container can access host files, host network resources, and credentials made available to it. Use trusted commands and images, and avoid mounting host paths or passing credentials unless the server needs them.
Authorize OAuth-backed servers
If a registered remote server requires OAuth, sbx mcp add starts the
authorization flow by default:
$ sbx mcp add notion --url https://mcp.notion.com/mcp
Resolving MCP server "notion"...
Open this URL to authorize MCP server "notion":
https://api.notion.com/v1/oauth/authorize?...
MCP server "notion" authorized
MCP server "notion" registered (type: remote)
OAuth credentials stay on the host. In local gateway mode, sbx stores tokens
in the host operating system's credential store.
To register an OAuth-backed server without authorizing it, pass --skip-auth:
$ sbx mcp add notion --url https://mcp.notion.com/mcp --skip-auth
Use a pre-registered OAuth client
In local gateway mode, you can register a remote OAuth server that doesn't support Dynamic Client Registration. If the server publishes OAuth metadata, pass the client ID that you registered with the server provider:
$ sbx mcp add slack --url https://slack.example.com/mcp \
--client-id <CLIENT_ID>
If the server doesn't publish OAuth metadata, pass
--oauth-authorization-server with the client ID. The flag accepts a local
file path or an HTTP or HTTPS URL to an RFC 8414 authorization server metadata
document. The document must define authorization_endpoint and
token_endpoint:
$ sbx mcp add serverx --url https://mcp.serverx.example/mcp \
--oauth-authorization-server ./serverx-authorization-server.json \
--client-id <CLIENT_ID>
These flags are only valid with --url.
For a confidential OAuth client, store the client secret before registering
the server. There is no --client-secret flag:
$ sbx secret set mcp:slack:client_secret
$ sbx mcp add slack --url https://slack.example.com/mcp \
--client-id <CLIENT_ID>
The client secret stays in the host credential store and isn't
written to the MCP registration. If the server requires a confidential client
and no secret is stored, registration succeeds but authorization is skipped.
Store the secret, then run sbx mcp auth <server>.
MCP OAuth client secrets use the name mcp:<server>:client_secret. The store
also maintains a mcp:<server>:client_secret:identity record that binds the
secret to the OAuth client. For secrets stored by a version that used
mcp:<server>.client_secret, set the secret again using the colon-separated
name.
Set OAuth scopes
Use the repeatable --scope flag to record the default scopes requested during
authorization:
$ sbx mcp add serverx --url https://mcp.serverx.example/mcp \
--scope read --scope write
The sbx mcp auth command accepts --scope to override the recorded defaults
for one authorization:
$ sbx mcp auth serverx --scope read
Unless you pass --no-scope, sbx requests the first available scope set in
the following order:
- Scopes passed to
sbx mcp auth --scope - Default scopes recorded by
sbx mcp add --scope - Scopes that the protected resource says it requires
- Whichever of
openid,email,profile, andoffline_accessthe authorization server advertises
If none of these provide a scope set, sbx omits the OAuth scope parameter so
the authorization server applies its default grant. Other advertised scopes
aren't included in the fallback.
Pass --no-scope to suppress the recorded defaults, resource-required scopes,
and advertised scope fallback for one authorization, without changing the
stored defaults:
$ sbx mcp auth serverx --no-scope
You can't combine --no-scope with --scope. Scopes you choose are checked
against the authorization server's advertised scopes and the resource's
required scopes. If either source publishes scopes, a scope present in neither
produces a warning but is still requested. The authorization server can still
refuse an advertised scope for a particular
client. For a local authorization flow, sbx lists the requested, advertised,
and refused scopes and suggests a retry command. If the server identifies the
refused scopes, the command removes them. Otherwise, it uses --no-scope.
sbx never retries automatically.
For each OAuth-backed remote server exposed to a sandbox, the gateway exposes a
helper tool named <server>-authorize, such as notion-authorize. The agent can
call the tool to authorize or reauthorize the server. If the server isn't
authorized, the helper is the only tool exposed for that server.
You can manage OAuth credentials from the host:
$ sbx mcp auth status notion
$ sbx mcp auth notion
$ sbx mcp auth rm notion
Use --all to apply auth, auth status, or auth rm to all registered
OAuth-backed servers. The auth status output reports the scopes granted by the
authorization server, the defaults recorded with sbx mcp add --scope, and the
scopes the server supports. It collapses duplicate scope names and highlights
granted scopes that weren't requested or are no longer in the supported set.
Use --json for machine-readable output:
$ sbx mcp auth status notion --json
Choose an MCP mode
Every sandbox starts an MCP gateway. When the sandbox starts, supported agent integrations read the gateway URL and register it with the agent.
Whether you pass --static-mcp when you create the sandbox determines its MCP
mode:
- Static mode pre-loads the specified servers and doesn't expose dynamic discovery tools to the agent.
- Dynamic mode pre-loads no servers and lets the agent find and attach registered servers.
This choice persists across sandbox restarts.
Use static mode
Pass --static-mcp to pre-load registered MCP servers:
$ sbx mcp add notion --url https://mcp.notion.com/mcp
$ sbx mcp add linear --url https://mcp.linear.app/mcp
$ sbx run claude --name my-session --static-mcp notion,linear
You can pass --static-mcp as a comma-separated list or repeat the flag:
$ sbx run claude --name my-session \
--static-mcp notion --static-mcp linear
Every name in the static set must already be registered with sbx mcp add. The
gateway doesn't expose mcp-find, mcp-add, or mcp-config-set to the agent.
You can't replace the initial set by passing --static-mcp when reconnecting to
an existing sandbox. To attach another server from the host, use
sbx mcp load.
Use dynamic mode
Omit --static-mcp to use dynamic mode. The gateway pre-loads no servers and
exposes mcp-find, mcp-add, and mcp-config-set to the agent. The agent can
search the registered server catalog and attach servers during the session.
If you run sbx mcp add after a dynamic sandbox starts, its gateway refreshes
the searchable catalog. The agent can then find and attach the new registration
without restarting. The sbx mcp add command doesn't attach the server by
itself.
Add a server to a running sandbox
To attach an already-registered server to a running sandbox, use
sbx mcp load. This works in both static and dynamic modes:
$ sbx mcp add linear --url https://mcp.linear.app/mcp
$ sbx mcp load linear --sandbox my-session
MCP server "linear" loaded into sandbox "my-session" (live)
Connected agent sessions receive a tool-list update, so the added tools become visible without reconnecting. The loaded server remains attached across sandbox restarts.
Built-in gateway tools
The local MCP gateway exposes a small set of built-in tools. These tools belong to the gateway itself, not to a registered MCP server. Agents can see and call them on the same MCP connection as server tools, so they can appear in agent tool lists, logs, policy decisions, audit logs, or approval prompts.
You don't need to call these tools directly for normal setup. Use sbx mcp
commands to register servers and manage credentials from the host. The tools
matter because agents can call them during a session, and admins can govern
them separately from tools provided by registered MCP servers.
| Tool | Description |
|---|---|
mcp-exec | Executes a tool by name through the gateway. |
code-mode | Creates an ephemeral JavaScript tool that can call selected tools through the MCP gateway. |
mcp-find | Searches the registered server catalog without changing sandbox state. Dynamic mode only. |
mcp-add | Attaches a registered server to the sandbox. Dynamic mode only. |
mcp-config-set | Sets per-session configuration overrides for an attached server. Dynamic mode only. |
<server>-authorize | Starts or restarts OAuth authorization for an exposed OAuth-backed remote server. |
Servers attached with mcp-add remain attached across sandbox restarts. The
gateway exposes <server>-authorize for OAuth-backed remote servers, even when
they already have a valid token. Local stdio servers don't expose this helper.
If code-mode creates a generated tool, the tool is shared by clients connected
to the sandbox's gateway and disappears when the gateway is replaced or stops.
In MCP access policies, built-in gateway tools are MCP::Primordial resources
and use the invokePrimordial action. Tools from registered MCP servers are
MCP::Tool resources and use the invokeTool action. For details, see the
MCP policy reference.
Manage registrations
List registered servers:
$ sbx mcp ls
Inspect a registered server:
$ sbx mcp inspect notion
Remove a registered server:
$ sbx mcp rm notion
For OAuth-backed servers, sbx mcp rm removes the OAuth access token before it
removes the server registration. A client secret for a pre-registered OAuth
client and its identity binding remain in the host credential store so you can
reuse them when you re-add the same client. The command prints the
sbx secret rm commands for removing them. To remove only the OAuth access
token, use sbx mcp auth rm.
Governance
Organizations with AI Governance can use MCP access policies to control MCP server registration, tool calls, gateway meta-tools, resources, prompts, and approval requirements. MCP access policies are organization policies written in Cedar.