A new site through MCP starts from a template the operator already trusts
Until this release an assistant connected through MCP could only update release targets an operator had configured in advance. It can now create a new one on the same server by deriving it from an operator's template, without supplying a command, path, image or registry.
Published 13 November 2026. Hostwatch engineering review; implementation limits are stated below.

A new site had no target to receive it
Hostwatch has a remote MCP server, which lets an AI assistant work on a customer's servers through a short catalog of named operations. MCP is the Model Context Protocol, the protocol an assistant uses to call tools on a remote service. Every release operation in that catalog is addressed to a target. A target is a release profile for one component of an application, such as its website, installed on the server by the operator, meaning the person who administers that server and edits the agent's configuration. It fixes the build recipe, the registry destination, the container's user and command, its loopback port, its resource limits and its health check. With a target in place, an owner of the workspace can inspect the approved source, upload an archive, build an image, publish it and deploy it.
That arrangement left a gap for one of the most ordinary requests an owner can make: put a new site on this server. The assistant could prepare the source, but there was no target to upload it into, and creating one meant an operator opening an SSH session and editing the agent configuration by hand. A new site could not be set up through MCP at all. The release of 12 November closes the gap with four operations. The operation components lists what exists, component_preview shows what a new one would look like, component_create makes it and component_remove forgets it. What they create is called a managed component, shortened to component in the rest of this article. It is an ordinary target whose settings the agent derived from an existing target on the same server instead of reading them from the operator's configuration file.
What a remote caller must not be able to supply
Creating a deployable thing normally means describing it. Someone writes down how the image is built, which registry receives it, which command starts the container, which host directories are mounted into it, which environment file it reads and which port it publishes. Each of those fields is harmless in the hands of the person who administers the server and dangerous as a parameter of a remote request. A command is arbitrary execution. A host path is a way to read or overwrite files that belong to another application. An image reference runs code that nobody on that server reviewed. A registry address is a place that built images, and whatever is inside them, can be sent to. A port mapping can put a private service on a public interface.
An assistant makes the problem sharper, because its requests are composed from text it has read: a repository, a log, a web page, a support ticket. If an operation accepts a command or a path, everything the assistant reads becomes a possible source of that command or path. The common answer is validation: accept the description and check each field against rules, which works until the rules meet a case their author did not think of. Hostwatch takes a narrower route and accepts no description. The caller points at something the operator has already configured on that server and asks for another one like it under a new name. Such a request has no field that could carry a command, a path, an image or a registry, so there is nothing of that kind to validate or to get wrong.
The request names a template and a new id
The existing target that serves as the model is called the template. An operator-configured target can be a template if it has both a source build profile, which is the installed recipe and limits for turning uploaded source into an image, and a deployment profile, which is the fixed description of the container. It must be on the same server as the new component, because what gets reused, the recipe file, the container runtime and the registry login, exists on that server and nothing is copied between servers. A target whose container belongs to a Podman pod is refused; containers in a pod share a network namespace, which is the opposite of what a separate new site needs. A managed component cannot be a template either, so every component stays one step away from a profile that a person installed.
The caller supplies two required values and may adjust four more. The id is three to forty lowercase letters, digits and hyphens, starting with a letter. That narrow alphabet matters because the id is reused as the target name, the container name, the local image name, the registry repository and a directory name. A value that ends up embedded in that many places is checked once, strictly, on the way in. The templateId names the template. Optionally the caller sets containerPort, the port the application listens on inside the container (1024 to 65535, default 3000), memoryMb and cpus for the container's limits, and healthPath, the URL path that the health check requests (the root path by default).
Each optional value can only narrow what the template allows. Memory and CPU may equal the template's limits or be lower, never higher. When they are omitted, the agent uses at most 512 MB and half a CPU, or the template's own limit where that is smaller. The health path must be a plain absolute path with no parent-directory segments, and the agent appends it to a loopback address that it chooses itself, so the caller cannot point the agent's health check at some other host. The control plane builds the request it sends to the agent from these six fields and, on creation, the previewed revision. An extra property added to the request by a confused or manipulated assistant is dropped before it reaches the server.

What the component takes from its template
The component reuses the parts of the template that describe how code becomes a running container, because those are the decisions the operator has already reviewed. It gets the same container runtime. It gets the same builder recipe, so its image is built by the same Containerfile under the same build limits for upload size, file count, memory, CPU and network policy. It runs as the same non-root user and starts with the same command. It keeps the template's process limit, temporary filesystem size and restart policy. For a second Next.js site beside an existing one this is exactly the wanted result: the new site is built and started the way the first one is, and nobody had to restate how.
The registry is inherited with one change. The component publishes to the same registry host and namespace with the template's registry credentials, the repository name is replaced by the component id and the tag stays as it was. The agent refuses the request if the template's destination cannot be renamed that way, or if another target already uses the resulting name. The caller never sees the credentials and never types a registry address. One practical consequence falls to the operator. If the registry account used on that server is restricted to particular repositories, it has to be allowed to push the new one, because Hostwatch does not change registry permissions.
What is deliberately left behind
Five things in the template never reach the component: its environment file, its secrets, its data mounts, its source files and its domains. The reason lies in the one part of a component that the caller does control, which is the source. Whatever archive the owner uploads will be built by the operator's recipe and run inside the new container. If the environment file came along, that code would start with the template's database password and API keys. If the mounts came along, it could read and write another application's data directory. If the domains came along, requests meant for the existing site could be answered by the new one.
Leaving them out makes the starting state easy to reason about. A new managed component is a container definition with the operator's recipe, user and limits, an empty source tree, no credentials, no persistent storage and no public name. The preview states this in two lists, inherited and not inherited, so the assistant and the person approving the call read the same boundary. The rules for every configured deployment still apply: the container runs as a non-root user with a read-only root filesystem, dropped capabilities, no new privileges, bounded memory, CPU and process count, and a port bound only to IPv4 loopback.
The cost is that this path suits applications that need neither secrets nor stored data to start: a static or server-rendered site, a documentation site, a small stateless service. An application that needs an API key, a database address or a directory that survives a redeploy is not finished by component_create. The operator adds the environment file reference or the mount to the agent configuration separately, through the same reviewed route as any other profile change, and there is no MCP argument for either. An application that writes caches into its own directory will also meet the read-only root filesystem, with only a small temporary filesystem available for writing.

How the port and the source directories are assigned
Everything the request does not contain is derived by the agent. The container takes the component id as its name, and the local image that the builder produces is named after the id as well. The host port comes from a block of one hundred loopback ports reserved for managed components, 3400 to 3499. The agent takes the lowest port in that block that no existing target binds and that nothing on the server is listening on, which it tests by briefly opening the port itself. The container's port is published only on 127.0.0.1 at that host port, and the health URL is built from the same address and the health path.
A host port chosen by the caller would be a small thing to allow and a lasting source of trouble. Two requests could choose the same number. One could choose a port that a database on the server already uses. A mapping written without an explicit loopback address would listen on every interface. Assigning from a reserved block removes all three cases and gives the operator one predictable range to keep clear. The assignment is recorded in the component, so no other Hostwatch target receives that port. It is not an operating-system reservation, though. Nothing is started at creation, so a process launched by hand could still take the port before the first deployment, and the range is best kept free of other software.
Source lives in two directories. The approved source directory is created empty under the agent's own state directory, in a location named after the id, and the build workspace sits beside the template's workspace. The preview refuses to continue if either location already contains files. The component itself is stored in a private state file next to the agent's publication job state and is loaded when the agent starts, so it survives a restart. A stored record is validated with the same rules as an operator-configured target. An invalid record is skipped and logged, and it never prevents the configured targets from loading. There is also a fixed cap on how many managed components one server can hold.
Preview first, then create exactly what was previewed
The operation component_preview only reads. It returns the template, the runtime, the derived local image name and registry destination, the container name, the port mapping, the health URL, the memory and CPU limits, a digest of the builder recipe, the inherited and not-inherited lists, the next steps and a revision. Private operator paths, such as the location of the recipe or the registry login file, stay out of the response. Before answering, the agent checks the conditions that would make creation unsafe: the id is not already a target, no container has that name, no local image already uses the component's image name, the source directories are empty and the template's recipe can be read.
The revision is a hash over every derived value. component_create takes the same fields plus that revision as expectedRevision, derives the component again and compares the two. If anything differs, the call is refused and the caller is told to preview again. This covers two situations. A request altered after the preview, for example with a higher memory limit, cannot reuse the earlier revision. And if the server changed in between, for instance because another component took the port that had been offered, the stale request fails instead of creating something the owner never saw. The earlier article on service placement describes the same pattern for publication and deployment previews.
Creation itself does very little, and that is intended. It makes the empty source directory, validates the derived target with the rules used for configured targets and writes the component to the agent's state. Nothing is built, published, started or exposed. The call is refused while another image job is running on that server. Afterwards the component appears in the components listing with its template, port and health path, and source, publication and deployment operations can address it by its id like any other target. It has no image and no container yet, which makes a mistaken creation cheap to undo.
A component starts unbuilt, so its first build is full
For an established target, a source preview compares the image that currently carries the target's local name with the approved baseline and refuses if they differ, because a difference means the image was changed outside the approved source history. A new component has no image and no baseline. The agent therefore gives it a baseline that no built image will have: the unbuilt marker, written as sha256: followed by sixty-four zeros. The source preview reports this marker as the source digest and the build request carries it back as the expected digest. The first build must use mode full. Partial mode overlays uploaded files on the approved current source, and an empty tree gives it nothing to overlay, so the archive has to contain the complete application.
A second rule guards against a name collision. If an image with the component's local name appears while the component is still unbuilt, whether at preview time or during the build, the operation fails and the operator has to reconcile it, so an image that arrived from somewhere else cannot quietly become the component's first release. After a successful build the sequence is the usual one with the values a first release needs: the registry tag is absent, so image_publish creates it, and no container exists, so deployment_create is called with the literal expected revision absent. Later releases may use partial or full mode as for any target. Archive rules, upload handling and the difference between the two modes are described in the earlier article on partial and full source releases and are unchanged here.
At that point the site answers on a loopback port and nowhere else. Publishing it on its own domains is a separate set of operations around component_ingress, which work through the server's shared Nginx in explicit stages for HTTP, the certificate and HTTPS. They are the subject of a separate article.

Removing a component, and who is allowed to ask
The operation component_remove takes the id and forgets the component. It applies only to managed components; a target that the operator configured cannot be removed this way. It is refused while the component still has a container or an installed ingress stage, so the order is to remove the ingress, delete the deployment and then remove the component. Removal deletes the record and nothing else. Built images, registry tags and source releases stay in place for retention, and no application data is touched. One consequence is worth knowing in advance: creating a component again under the same id is refused while its old image or source files are still on the server, until the operator has reconciled them.
All four operations are owner-only, including the two that only read, since a listing of components describes private deployment details. The two that change something, component_create and component_remove, also require the write scope on the assistant's OAuth connection and an explicit confirmation on the individual call. The control plane checks the role and the scope before it forwards anything, and the agent checks the owner role and the confirmation again on its side. An owner whose assistant holds a read-only connection can list and preview but cannot create.
Each server's agent also applies its own MCP governance policy, which an MCP client cannot change. The policy knows every component operation by name and classifies it as observing or changing. It can block a single tool, switch off all changes that arrive through MCP or limit how many changes are accepted per hour. It also checks that the tool name matches the route and method it is used with, so a request labelled as a preview cannot reach the create route. Every allowed or denied operation is logged with the client's identity, and successful changes are recorded in the Hostwatch audit log. When governance denies a call, the assistant should report the denial to the owner; a denied permission is no reason to look for another route.
What remains the operator's job
The template is the operator's work, and it is where the trust in this design sits. Someone has to install a target with a reviewed recipe, a registry destination, a non-root user, sensible limits and a health check before any component can be derived from it. A server without a suitable template offers nothing to copy, and the assistant should report that as a missing requirement instead of improvising. Templates deserve deliberate choice. Every component made from one is built and started the same way, so an unpinned base image or a careless start command is copied along with everything else, and only the memory and CPU limits can be tightened per component.
Several things stay outside these operations by design. Secrets and persistent data are added by the operator in the agent configuration. DNS records belong to whoever controls the domain. Registry permissions, registry garbage collection and image signature policy are administered on the server. Backups, restore checks and operating-system maintenance are unchanged. The deployment health check establishes that the configured URL answers and that the expected image is running; whether the new site works for a visitor still needs a representative request or a person looking at it. The uploaded code is the owner's responsibility as well, because Hostwatch builds what it was given.
Availability depends on the agent version installed on each server. Agents that include this release offer the component operations; a server with an older agent keeps working as before and does not offer them until its agent is upgraded, which is an operator task carried out server by server. Our record of this release is also specific about what was exercised where. Creation, the bounds on requests, the full-mode requirement for a first build and the refusal to remove a component that still has ingress are covered by the agent's automated tests. Against a live server, the check made after the upgrade was the read-only preview, which returned the derived registry destination, loopback port and limits and created nothing. The first component on any server deserves the same care: preview it, read every derived value, then decide.
A managed component copies how the operator's template is built and run, takes a new name and a loopback port from a reserved range, and inherits no environment file, secret, mount, source or domain. Preview it, create it, give it a full first build, and leave secrets, DNS and verification with the people responsible for them.
Further reading
- Hostwatch: update a component, files or a complete service ↗
- Hostwatch: create a new site and publish it on its domain ↗
- Hostwatch blog: partial edits and full source replacements need different promises ↗
- Hostwatch blog: service placement is the starting point of a trustworthy release ↗
- Podman: podman-run reference for publish, user, read-only and resource options ↗