Skip to main content
Glama

CreateProject

Creates a project from its files and deploys it. Waits for the deploy (wait_seconds) and answers with the operation and, once it ended, the project: its URL, its services' states, its problems. violations instead = nothing was created: change what each says, call again. SUCCEEDED says the containers run and listen, not what a page answers: open the URL once (401 = its password page).

Files, one of: the directory as it is on your disk, as an archive (CreateTransfer, then upload_id): nothing is retyped; files, text you send yourself, when there is no directory or no shell (never a file you have not read); source.github. /.env holds the secrets (env_file: .env). The compose file is the root's pethost.compose.yaml (so the repository's compose.yaml stays for development), else compose.yaml, compose.yml, docker-compose.yml or docker-compose.yaml; it becomes /compose.yaml, other compose and override files are dropped. Without one, a Dockerfile yields service app (reading /.env if any, its EXPOSE ports, a named volume per VOLUME of its last stage).

A database (Postgres or Valkey) is CreateDatabase's.

compose.yaml rules. Data lives in named volumes; all else a container writes is lost when it is recreated. Project files are bind-mounted read-only. HTTP comes through the proxy, to a host of a route in x-pethost, the one extension read, in the file or as x_pethost:

x-pethost: metadata: {name: Recipe Box, emoji: "🥗", description: One line, notes: Free text} routes: - {host: recipes.sam.pethost.app, service: web, port: 3000} - {host: recipes.sam.pethost.app, path: /api, service: api, port: 8000, strip_path: true}

ports: stays as the file has it, and is never refused. A TCP port it publishes that answers HTTP gets its route by itself and is not opened on the machine: at <project>.<Machine.apps_domain>, or <project>-<service>.<apps_domain> each when the project has several; Project.url has it when the call answers. Any other published port opens on the machine as written, at <Machine.hostname>:<port>, and one that is taken there fails the deploy; so does a web port once its route is removed. Never opened: a port bound to 127.0.0.1 (ssh_command tunnels to it), a machine port of the machine's own (80, 443, 22), and one nothing listens on within a minute of its start, until a later deploy finds it listening (Service.published_ports lists what is open). With x_pethost.routes the routes are yours and the machine names none. A project that publishes no port gets <project>.<apps_domain> in its first deploy, for the one port it listens on. A service with neither is private: the project's services reach it at <service>:<port>. A password for visitors goes only as x_pethost.password, never into the file: every route then answers 401 with a password page, over HTTPS only; nothing returns it (Project.password_protected says it is set); and files that write /compose.yaml keep the password_hash line the machine put in its x-pethost. All of compose.yaml is interpolated: $$ for $.

The file runs as written, or is refused: the machine corrects nothing in it, in any version. Refused, each violation saying what to write instead:

  • a volume's name; driver (but Docker's default, local or bridge), driver_opts, external or ipam of a volume or network: remove them.

  • a writable bind mount of the whole project (.:/app): add :ro.

  • a volume with no name (- /data): name it. Below a bind mount it is allowed, as scratch space (/app/node_modules).

  • env_file naming a file the files lack: write it, empty if it sets nothing, or give the entry required: false.

  • privileged, cap_add, security_opt (but no-new-privileges), devices, host namespaces, the Docker socket, a path outside the directory; more than one replica; include or extends from a URL; a git URL as a build context. Not refused, and read the machine's way: a container_name and a network's name name nothing on the machine, so two projects may write the same (the project's services still reach the container by it); a service with profiles runs only while COMPOSE_PROFILES in /.env names one of them, and is no service of the project until then; a bind mount of a folder without :ro (./data:/data) mounts the project's volume named after the path (data), which deploys keep and backups hold, with none of the version's files in it, so project files take :ro, and data is plainer in a named volume (data:/data, with data: under volumes:); a bind mount of a file without :ro mounts it read-only. An image's VOLUME that no mount covers fails the deploy (UNCOVERED_IMAGE_VOLUME): mount a named volume or a tmpfs there.

ALREADY_EXISTS = the id is taken (a retry with its operation_id returns that operation). FAILED_PRECONDITION = the GitHub App cannot read the repository (see GetMachine.github), or no such branch or directory. A deleted project's id inherits its snapshots.

Input Schema

NameRequiredDescriptionDefault
filesNoThe project's files, e.g. [{path: "/compose.yaml", text: "…"}, {path: "/.env", text: "…"}], or those to write over the archive's or the commit's. A github source takes only /.env.
sourceNoSet = a GitHub project: {github: {repository}}. Absent = the files of this request. Where the files come from (THE PROJECT IS ITS DIRECTORY). At most one of files, github.
upload_idNoAn archive of the project's directory, from CreateTransfer.upload_archive, unpacked first. FAILED_PRECONDITION = not arrived; NOT_FOUND = expired or used. One the machine refused (its PUT said why) answers with its `violations`.
x_pethostNoChanges to the files' x-pethost: the name people see, the routes, a password. x-pethost as data. Absent parts stay.
project_idNoNew, [a-z0-9][a-z0-9_-]*, ≤63 chars; immutable.
operation_idNoAs DeployProject's operation_id.
wait_secondsNoAs DeployProject's wait_seconds.
timeout_secondsNoAs DeployProject's timeout_seconds.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed1 schema field changed
    • removedInput schema / properties / database
      Removed value: -{
      -  "description": "Set = a database (Postgres or Valkey) the machine writes and deploys; leave files, upload_id, source, x_pethost out.",
      -  "enum": [
      -    "DATABASE_ENGINE_POSTGRES",
      -    "DATABASE_ENGINE_VALKEY"
      -  ],
      -  "type": "string"
      -}
  2. Changed1 schema field changed
    • addedInput schema / properties / database
      Added value: +{
      +  "description": "Set = a database (Postgres or Valkey) the machine writes and deploys; leave files, upload_id, source, x_pethost out.",
      +  "enum": [
      +    "DATABASE_ENGINE_POSTGRES",
      +    "DATABASE_ENGINE_VALKEY"
      +  ],
      +  "type": "string"
      +}
  3. First observed

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the annotations it discloses that the call waits for the deploy, what the response contains (URL, service states, problems), the meaning of `violations` (nothing created, retry after fixes), that SUCCEEDED does not mean the page serves, the 401 password-page caveat, and the ALREADY_EXISTS/FAILED_PRECONDITION semantics. This is exactly the extra behavioral context annotations cannot convey.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The core action is front-loaded well, but the body expands into a long compose-file rulebook (volumes, ports, refusals, interpolation). Much of that knowledge is necessary for a successful call, yet it reads as an embedded manual rather than a description, which hurts scanability.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a complex eight-parameter nested deploy tool with no output schema, the description covers sources, response shape, error codes, and the deployment contract thoroughly. Nothing an agent needs to invoke it correctly is obviously missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the schema already documents every field, but the description still adds substantive meaning: the precedence of pethost.compose.yaml over compose.yaml, what an upload_id requires, how `source` interacts with `files`, and the x_pethost route/password semantics. This goes well past the schema descriptions.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The first sentence states a specific verb and resource — 'Creates a project from its files and deploys it' — and the description then positions the tool against siblings by assigning databases to CreateDatabase and archives to CreateTransfer. An agent can tell this apart from DeployProject without opening either schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives clear conditions for each file source (directory, CreateTransfer archive, `files`, `source.github`) and explicitly routes databases and archives to sibling tools. It does not, however, explicitly state when to prefer this over DeployProject for an existing project.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.

Resources