Container services
Run personal software from a public container image on ClosedMCP. Choose a private browser interface for a web application, or interface:"none" for an always-running worker with no inbound endpoint. Use Serverless MCPs when publishing MCP tools from source code. A container service does not automatically become an MCP tool or receive a user's connected-account tokens.
Create and open an app
In the console, open Container services, choose or create a project, enter a service name, image version and HTTP port, then review and create. ClosedMCP resolves the image to an immutable digest. The app receives a stable private HTTPS URL. Open app signs the owner in on a separate app domain; copying its URL does not grant someone else access.
The image must run as a non-root user (UID 1000 by default) and work with a read-only root filesystem. A web application must listen on 0.0.0.0 at the configured port. /tmp is temporary writable memory. The HTTP port can be 1024 through 65535. Web readiness requests / and expects HTTP 200–399; a worker has no HTTP probe, port declaration, ClusterIP application Service or inbound network grant. Worker ready confirms a running process, not completion of its application jobs. There is no public TCP, SSH, UDP, host networking or Docker socket.
Agent workflow
Start with closedmcp_services and check runtime_enabled. If false, explain that this installation cannot run containers yet. You may prepare or edit a configuration if the user wants, but do not request keys, promise startup, or keep polling for readiness. The platform operator must enable the runtime first. Plans and service status repeat this field. A true value means a runtime is configured; only the service's ready state confirms its current revision passed its runtime check.
Find a project using closedmcp_projects, or create one with closedmcp_create_project. The signed-in human must own it and have deployment permission. Plan before applying:
{
"project": "PROJECT_ID_FROM_THE_TOOL",
"name": "my-web-app",
"config": {
"image": "docker.io/traefik/whoami:v1.11.0",
"port": 8080,
"environment": { "WHOAMI_PORT_NUMBER": "8080" }
}
}Send that object to closedmcp_service_plan. Show the image, port, internet destinations, storage and restart impact to the user. Call closedmcp_service_apply with {"plan":"RETURNED_PLAN_ID"}. A plan lasts 15 minutes. Repeating apply with the same plan recovers the same operation; do not create a replacement service because a request timed out.
Call closedmcp_services with {"service":"RETURNED_SERVICE_ID"} to read state. ready means the current revision passed its runtime check. needs_setup requires owner approval of keys or management scopes. Read capabilities for the actual inbound port (null for a worker), currently approved management scopes, writable roots, authenticated console link and next action. Open that console link and use Open app for browser access; it is not an MCP tool or a raw public endpoint. Poll pending status at a reasonable interval, such as five seconds. List services with {}; paginate with after set to the last returned ID.
To run a worker, set interface:"none" and omit port. The image's original entrypoint is preserved unless entry_command supplies an explicit argv list; no shell is implicitly added. For example, a supported Python image can run ["python","worker.py"] when that file is already in the image. An always-running worker must keep its main process alive. This mode does not publish MCP tools. Interactive exec/files management is a separate capability; never treat a denied MCP tool as permission to execute commands.
Manage compute and files
Request only the needed config.management scopes: run, read_files (also list) or write_files. Default is none. Even a worker with no keys waits for explicit owner approval in the authenticated setup console. A command can read the app's environment and approved keys. A file read can reveal data the image saved in temporary storage. Management never receives the platform's connected-account tokens or Kubernetes credentials.
Use the existing closedmcp_run, closedmcp_read_files, closedmcp_write_files and closedmcp_list_files tools with service instead of project. Project calls retain their sandbox/Git behavior. For a container, run takes explicit argv, optional cwd (default /tmp) and timeout_seconds (1–60, default 30); there is no implicit shell. Files use absolute paths under capabilities.writable_roots. Run/write require a unique idempotency_key per intended operation. Reuse the same key after a lost reply: it cannot dispatch again within 24 hours, even when the outcome is unknown. Full replies are encrypted and kept for ten minutes or the last ten replies; later recovery returns the saved outcome only. At most one management operation runs per service and 1,000 new operations per day. Do not silently repeat a mutation with a new key. Inspect files using a new read operation, or stop the service to cancel its compute.
Read/write support at most 16 files and 64 KiB total UTF-8 data; list returns at most 200 entries. Commands return at most 64 KiB output and report truncation, exit status, deadline and descendant cleanup. A multi-file write replaces each file atomically, but can return a partial result listing files already written. Management preserves the main container, its Pod identity and restart count. Image/settings/resource changes replace it and revoke prior management approval. Current membership, workspace, project ownership, deploy role and AI-app policy are checked on every call. An explicit group destination uses the existing group selection and app approval policy; a group credential cannot hop groups.
Optional resources chooses cpu_millicores 100–1000, memory_mib 128–1024 in steps of 128 and scratch_mib 8–256 (at most half the memory). Defaults are 1000, 512 and 64. Memory is reserved, CPU has 100 millicores reserved with the configured burst limit, and memory-backed scratch counts toward the same memory limit. Changing these settings restarts the process and loses temporary files.
Private key setup
Declare environment names, for example "keys":["GITHUB_TOKEN"], in the configuration. Call closedmcp_service_setup_link with the service ID and give its returned link to the user. The link opens the console and requires login as the original owner in the correct workspace. The owner reviews the exact image and enters the values there. Never ask for credentials in chat, put them in public environment settings, or pass them through an MCP tool.
The link is single use, lasts 30 minutes and is bound to the service revision. An expired or stale link cannot change keys: request a new one. Reads reveal only whether each key is saved. Values are encrypted at rest and delivered only to the approved revision as environment variables. The application can read those values. ClosedMCP does not make an untrusted image safe to receive a sensitive credential; the owner must choose an appropriate credential and image.
Image, listener and environment edits require fresh key approval if the service declares keys. Destination/port policy edits retain the existing approved process and key delivery. If a process holds approved keys or management permissions, widening its network access requires the owner to review and approve the exact destinations in the authenticated console; tightening applies immediately. A saved value can be retained by leaving its field blank. Removing a key from the configuration prevents delivery to later revisions. Updating keys restarts the app. Project transfers never transfer keys or browser access.
Edit a port or image
Open the service, change HTTP port or image, review, and apply. The URL remains the same. The app restarts and brief downtime is expected. Port configuration describes where the gateway connects; it does not reconfigure the application itself. If the application uses a setting such as PORT, change that public setting too.
Agents first read the current configuration and generation, then plan with the same project and name, the complete new configuration and expected_generation set to that generation. A concurrent edit rejects the stale plan. Read status again before preparing a new plan. Use the old immutable image digest in a new plan to roll back an image; data migrations are not automatically undone.
Internet access and storage
Internet access is off by default. Set egress to exact public hostname and TCP port pairs, for example [{"host":"api.github.com","port":443},{"host":"api.example.com","port":8443}]. The older https_hosts field remains shorthand for TCP443; grants in both fields are combined. Clients must use HTTP CONNECT through the supplied authenticated proxy; common HTTPS clients honor HTTPS_PROXY. Direct sockets and DNS are blocked. Each DNS answer is checked and the checked address is connected; private, metadata and platform infrastructure addresses remain denied on every port. Redirects to another destination need a separate grant. Proxy-aware TCP clients can use an approved port; direct SSH and clients that bypass the proxy are unsupported.
Use the same plan/apply flow to edit only outbound grants. The plan returns restart_required:false; applying advances generation while preserving runtime_generation, the process and its temporary files. New connections use the current policy immediately. Existing tunnels are rechecked every five seconds, with a one-second authorization timeout that fails closed, giving a six-second revocation bound under normal runtime scheduling. Image, listener, settings, key and lifecycle changes restart the process. Only callers acting with the current owner's account and deployment permission may prepare destination changes; the workload's proxy credential cannot change policy. When widening access for a process holding approved keys or management permissions, the plan returns requires_network_approval:true and network_approval_url. Return that link to the owner, wait for console approval, then read status. An MCP call cannot approve this widening. The owner reviews the exact image, current and proposed destination/port pairs and saved key names. Tightening needs no extra approval and preserves the process. Repeating the approved plan recovers its result. Native third-party credentials still have to be entered/configured for that application; a GitHub connection in ClosedMCP is not automatically an n8n credential.
Optional volume has path and size_gib (1–10). Persistent storage starts only on an installation whose operator has qualified capacity enforcement and exclusive single-writer mounts. The default local-path provisioner is rejected. Without qualified storage the service is visibly blocked; temporary storage is never substituted. Existing volume paths and sizes cannot be edited. Stateful applications such as n8n require a separate image and storage qualification before use.
Stop and delete
closedmcp_service_stop takes a service ID and revokes browser and proxy access immediately; existing streams close within six seconds under normal runtime scheduling. The process then shuts down. Editing and applying its configuration restarts it, with fresh key approval when applicable.
closedmcp_service_delete additionally requires confirm_name equal to the exact service name. It removes runtime access and key delivery. Persistent data is retained for operator recovery; self-service restore and purge are not implemented. A deleted name cannot be reused in the same project. Never report deployment or deletion complete until status confirms it.
Current limits
- One container, either one private HTTP interface or no inbound interface; one replica, no automatic scale-out.
- Public Docker Hub and GHCR images only, with an explicit version or digest. No private registry credentials.
- Ten active services per owner. Default 512 MiB memory/one-CPU limit, with bounded resource choices above; startup can wait for qualified worker capacity.
- Owner-only browser access, sessions up to one hour, uploads up to 8 MiB. HTTP streaming and WebSockets are supported; web/service workers are disabled to prevent a previous image intercepting later sign-in.
- No public webhooks, shared app access, raw application logs, private network access or automatic downstream-account delegation in this version.
- Runtime availability is installation-specific. A saved plan does not prove that the installation has enabled or qualified deployment.
For an already-built MCP image, use the project closedmcp_publish image option described in Serverless MCPs. It uses the MCP gateway, readiness, caller identity and app-version lifecycle. A generic Container service's web route does not register MCP tools, and image MCP publishing does not require creating one or exposing a raw public MCP port. The two capabilities are enabled and qualified separately.
After an unknown management reply, retain the operation key and wait until its returned busy_until before a new inspection, or stop the service. A verified not_started result confirms no operation started; its key stays consumed, so a later intended attempt uses a new key.
For AI agents: this page as markdown is at /docs/container-services.md, and the closedmcp_guide tool returns it with topic services.