# Deploying your environment (https://www.agentenvframework.com/docs/environments/deploying)

> Package, register and deploy an environment, use it through its card, and tear its instances down

Deploying runs your server in a sandbox, an isolated machine or set of containers that the
framework starts for it. This page deploys the `EmailEnv` from
[Creating your own environment](https://www.agentenvframework.com/docs/environments/creating.md). You register the environment once,
and then deploy it as often as you need. Each deploy is a new env instance, with its own id, its
own inbox and its own URLs.

1. Register the folder. The put builds the image and stores the env `email`, version 1.
2. Deploy it with `--sandbox local`. The local sandbox starts an env instance, with its own id, behind a gateway.
3. The framework reads the card the instance serves: its name, endpoints and tools.
4. `data/add` loads Dana’s email into the inbox through the data plane, `/agentenv`.
5. An agent connects to `/mcp` and calls the tools: `email_search`, then `send`.
6. `data/get` reads the inbox and the sent folder back, and `data/reset` empties them.
7. Deploy the same version with `--sandbox modal_vm`: a new instance in another sandbox, with a new id and a new card.

Parts of the scene:

- **Your folder**: `server.py` holds `EmailEnv`, and the `Dockerfile` packages it into the image the framework deploys.
- **Version 1 of email**: What `agent-env env mcp-server put` stored: an env that points at the image the put built. It runs nothing, and a later put adds version 2 without changing this one.
- **The commands**: `agent-env env mcp-server put` registers the env, `agent-env env deploy` starts an instance in the sandbox its `--sandbox` names, and `teardown.py` closes one from Python.
- **The --sandbox option**: Picks the sandbox each deploy runs in, so the same version can run in any of them: a built-in such as `local` or `modal_vm`, or one you register in `config.toml`. Without it, a deploy uses `[sandbox] default` from `config.toml`, which is `local` unless you change it.
- **The local sandbox**: Where `--sandbox local` runs an instance: each part is a container on your machine’s Docker. It does not enforce the TTL, so close its instances yourself.
- **The Modal sandbox**: Where `--sandbox modal_vm` runs an instance: one Modal VM with Docker inside, where each part of the instance is a container, as it is locally. The VM loads the images from your object store, and it needs your Modal credentials.
- **An env instance**: One deployment of `email` version 1, with its own id: the env id plus eight random characters. `agent-env env get-instance --id` reads its record back.
- **The gateway**: The default topology puts it in front of your server. It forwards `/mcp` and `/agentenv` to the server and adds extensions of its own, such as a virtual clock and triggers.
- **Your server**: `EmailEnv`, running from the image. Its tools and its data plane read and change the same `inbox` and `sent` lists.
- **An agent**: Connects to the instance’s MCP URL, `/mcp`, and calls `email_search` and `send`. It is never offered the data plane.
- **The framework**: Polls the instance’s card until the instance is ready, then uses the data plane, `/agentenv`: `data/add`, `data/get` and `data/reset`.
- **The instance’s card**: Served at `/.well-known/agent-env.json` and stored on the instance’s record. It lists the name, the paths of MCP and the data plane, and the tools; each deploy draws a new name.

## Package it

Start Docker before continuing; this tutorial builds and runs containers locally.

The framework deploys container images, so the first step is a Dockerfile next to `server.py`:

```dockerfile title="email/Dockerfile"
FROM python:3.12-slim
WORKDIR /app
RUN pip install --no-cache-dir agentenv-framework-protocol "mcp>=1.25,<2"
COPY server.py .
CMD ["python", "server.py"]
```

## Register it

Registering builds the image and stores it as an artifact, a stored object that the framework
versions. It then stores the env, a document that points at that artifact, under an id you
choose. These pages use the id `email`:

```bash title="Terminal"
agent-env env mcp-server put --id email --dockerfile email/Dockerfile
```

```text title="Output"
Derived environment_name='email' from the environment card.
Building MCP server Docker image...
Creating DockerImageArtifact...
Created artifact: id=mcp-server-email version=1
Creating MCPServerEnv...
Created MCPServerEnv: id=email version=1 environment_name=email env_provider_type=gateway
```

The first line of the output is the command reading the name `email` from `@environment_card` in
your source; [The environment card](https://www.agentenvframework.com/docs/environments/environment-card.md) explains what the name is
for. `env_provider_type` is the topology from [Choose the environment's
topology](https://www.agentenvframework.com/docs/environments/topology.md). Each put of the same id stores a new version and leaves the older ones
unchanged.

## Deploy it

Before your first deploy, the default topology needs `default-db` and `default` registered in your
current registry. Run each command below only if that env is missing; `agent-env up` may have
registered it already:

```bash title="Terminal"
agent-env env service-db put --id default-db
agent-env env gateway put --id default
```

With those envs and `email` registered, one command deploys it:

```bash title="Terminal"
agent-env env deploy --id email
```

```text title="Output"
Sandbox backend: config default
Fetching env: id=email version=latest...
Found env: id=email version=1 type=mcp_server
Deploying (ttl=10800s, gateway_mode=performance, disk=10.0GB)...
Deployed!
Instance ID: email-mmtflq6t
Env MCP Url: http://localhost:61655/mcp
Env Gateway Url: http://localhost:61655
Env DB Web Url: http://localhost:61656/
Env DB MCP Url: http://localhost:61657/mcp
Expires At (UTC): 2026-09-29 09:23 UTC
```

`Env MCP Url` is how an agent uses your environment's tools: an agent connected there can call
`email_search` and `send`.

Where the instance runs depends on the sandbox. The default is `local`, where each part of the
instance is a container on your machine's Docker. `--sandbox` picks another built-in, such as
`modal_vm`, or a provider you register under `[sandbox.providers.<name>]` in `config.toml`.

The framework records every instance. `agent-env env get-instance --id email-mmtflq6t` reads the
record back: the env id and the exact version it deployed, the instance's URLs, the sandbox it
runs in and when it expires. The record also stores the card the instance served, which
[The Environment Card](https://www.agentenvframework.com/docs/environments/environment-card.md#get-an-env-instances-card) shows.

## Use it

An agent uses your environment through the interfaces the instance's card declares. The card's MCP
interface gives the URL to connect to, and its name the MCP server the agent sees: `env4276` at
`http://localhost:61655/mcp`. In a [task](https://www.agentenvframework.com/docs/tasks.md), a `deploy_agent` step reads both from the
instance's record and hands them to the agent, which lists the tools the card advertises and
calls them.

1. The instance serves its card at `/.well-known/agent-env.json`: its name, its interfaces, its tools and its extensions.
2. The card’s MCP interface and name tell the framework where to connect an agent: `/mcp`, as the MCP server `env4276`.
3. The agent lists the tools the card advertises and calls them: `email_search` finds Dana’s email, and `send` sends the reply.
4. Extensions on the card declare other interfaces: the gateway’s `urn:agentenv:step/v1` serves the same tools over REST at `/step`.
5. A server that serves an interface manifest adds `urn:agentenv:get-interfaces/v1`, and a CLI can be built from it. `email` has none.

Parts of the scene:

- **The instance’s card**: Served at `/.well-known/agent-env.json` and stored on the instance’s record. Every client finds its interface here: its name, the MCP path, the tools and the extensions.
- **Extensions**: Each extension is a URN and the endpoints it serves. The framework uses an interface only when the card lists it, so the same code drives envs that offer different ones.
- **An interface manifest**: A server can describe its data model in an interface manifest and advertise it under `urn:agentenv:get-interfaces/v1`. `EmailEnv` serves none, so its card does not list it.
- **An agent**: Connected to the card’s MCP URL under the card’s name; in a task, a `deploy_agent` step hands it both. It sees `email_search` and `send`, and never the data plane.
- **A REST client**: Anything that speaks HTTP, such as a harness or a grader. `POST /step` with `list_tools` or `call_tool` reaches the same tools, filtered by the caller’s `AgentEnv-Role` header.
- **A CLI**: `agent-env env mcp-server create-cli --id` builds a command-line tool from a server’s interface manifest and its live tools, and stores it as an artifact.
- **The env instance**: `email-mmtflq6t`, from Deploy it: your server behind a gateway, with Dana’s email already loaded into the inbox through the data plane.
- **The gateway**: Serves `/mcp` with the tools of every server behind it, and adds `/step`, a REST route to the same tools, which its card declares as `urn:agentenv:step/v1`.
- **Your server**: `EmailEnv`, running from the image. `email_search` reads its inbox, and `send` adds to its sent folder.

Other interfaces are declared the same way, as extensions on the card, and the framework uses one
only when the card lists it. Behind the gateway, `urn:agentenv:step/v1` adds `/step`, which lists
and calls the same tools over REST, and a server that serves an interface manifest adds
`urn:agentenv:get-interfaces/v1`, from which `agent-env env mcp-server create-cli` builds a
command-line tool. [The environment card](https://www.agentenvframework.com/docs/environments/environment-card.md) covers every field.

## Tear it down

Deploying again starts another instance with another id, and the env itself never changes. An
instance runs until its TTL runs out, which you set with `--ttl-seconds`, or until you close it.
You close an instance from Python by its id:

```python title="teardown.py"
import asyncio

from agent_env.env import Env


async def main() -> None:
    env = await Env.from_instance_id("email-mmtflq6t")
    await env.close()


asyncio.run(main())
```

`Env.from_instance_id` reconnects to the instance's sandbox and `close()` stops it. In a
[task](https://www.agentenvframework.com/docs/tasks.md), a `deploy_env` step and a `teardown_sandboxes` step deploy and close instances
for you.

Every instance on this page ran behind a gateway, the default topology. [Choose the environment's
topology](https://www.agentenvframework.com/docs/environments/topology.md) covers the other shapes an instance can take.