Skip to main content
Glama

Server Details

Deploy and run your projects on Pethost, your own hosting.

Ownership verified
Status
Healthy
Uptime
100.0% over the last 24 hours
OAuth
Works in Glama
Last Tested
Transport
Streamable HTTP · MCP 2025-11-25
URL
ChatGPT
Pethost
Claude
Pethost

TDQS

A3.9/5.0

Scored across 21 tools

Disambiguation4/5

Most tools target a distinct resource or action (create/deploy/get project, link database, query logs/traffic), so selection is usually clear. A few boundaries are softer: RunProjectAction is an umbrella that overlaps with DeployProject and snapshot-related CreateDatabase behavior, while UI-only tools like Show, Mentions, and ProjectTab can be confused with data-read tools, though the descriptions mostly resolve this.

Naming Consistency4/5

Nearly all tools use PascalCase verb-noun naming (CreateProject, DeployProject, GetOperation, QueryContainerLogs, RunServiceCommand) with consistent Get/List/Query/Run/Set prefixes. The main deviations are noun-only or verb-only host UI tools (Mentions, ProjectTab, Show), which are minor but noticeable.

Tool Count3/5

Twenty-one tools is on the heavy side for the rubric's typical 3-15 range, and the surface includes several UI-oriented tools plus generic Run*Action endpoints that bundle many subactions. The broad Pethost domain does justify many tools, but the set still feels borderline heavy rather than tightly scoped.

Completeness4/5

The set covers the core lifecycle: project creation/deploy/get, database creation/linking, moves, backups/restore/delete via actions, logs/traffic, file access, alerts, and machine/service actions. Minor gaps remain: workspace management is only list/move with no create/rename/delete, and some destructive operations are hidden inside RunProjectAction rather than exposed as explicit tools.

Publisher details

Operator
Pethost
Operator website
https://pethost.dev
Vendor relationship
First-party
Trust center
Not available
Restrictions
Not applicable

Available Tools

21 tools
CreateDatabaseAInspect

A database project, Postgres, MariaDB (for an app that asks for MySQL or MariaDB) or Valkey: the machine writes its compose.yaml and /.env and deploys it, with no address. Make it before the app that uses it: the app reaches it at the host <project_id> once linked (the app's CreateProject link_databases, which may follow at once, as its deploy waits for this one; link or LinkDatabase for an app that exists, as the apps' user and writing nothing into its /.env), and Project.database says how to sign in. Or a copy of a database's snapshot, with passwords of its own and none of its links. Answers as CreateProject does. INVALID_ARGUMENT = an engine or a size Machine.database_engines does not offer, or a project_id with "_", that is a number or that every container's /etc/hosts names (it is the host name apps use). NOT_FOUND = no such snapshot or app. FAILED_PRECONDITION = the snapshot is of no database of that engine; + DatabaseLinkRefusal = an app of link cannot be linked, and nothing was created.

Inputs: link, engine, metadata, workspace, +5 more.

CreateProjectAInspect

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, MariaDB or Valkey) is CreateDatabase's: make the app's first, then link it here with link_databases, e.g. {database_project_id: "recipes-db", env_prefix: "DATABASE"}, and compose.yaml reads ${DATABASE_URL:?}. The app reaches each at the host <database_project_id> from its first start (its deploy waits for one still being made). own_user, on an engine whose offer has own_users (Postgres, MariaDB; a Valkey has one user), to share a database other apps use: a user and a database of its own, named as the project, which they cannot reach; all are restored together. Only link_databases makes one: LinkDatabase links as the apps' user. env_prefix "DATABASE": the machine writes DATABASE_URL, _HOST, _PORT, _USER, _PASSWORD and _NAME into /.env, so no password is copied. A name /.env sets already is refused, as a laptop's .env in an archive may set one: send files with a /.env without it beside upload_id.

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). An upload_id: FAILED_PRECONDITION = not arrived; NOT_FOUND = expired or used; one the machine refused (its PUT said why) answers with its violations. FAILED_PRECONDITION = the GitHub App cannot read the repository (see GetMachine.github), or no such branch or directory; + DatabaseLinkRefusal = a database of link_databases cannot be linked to it (database_project_id says which), and nothing was created. A deleted project's id inherits its snapshots.

Inputs: files, source, upload_id, workspace, +6 more.

CreateTransferA
Destructive
Inspect

A one-request URL moving one file straight between you and the machine: run command in a shell, or send http_method to url yourself, before expire_time.

  • upload_archive: the project's directory, packed, for CreateProject's or DeployProject's upload_id once the PUT answered 200 with what it holds.

  • upload_file: one file into a container or volume, replacing any file there (replaces), creating parents.

  • download: a file, or a directory as a .tar (file_name).

  • download_database: a database project's dump, made as it downloads: Postgres's for pg_restore (roles are not in it), MariaDB's SQL of one database for its console, mariadb <database> < file (users are not in it), Valkey's .rdb. One at a time per database. Plain-text answers: 404 used or expired URL, 409 FAILED_PRECONDITION, 413 archive over 2 GiB, 422 unsafe archive (a reason per line), 503 UNAVAILABLE, 507 disk full. A failed transfer keeps nothing: get a new URL. Errors as ReadPath; FAILED_PRECONDITION also = downloading neither a file nor a directory, uploading onto a non-file, a mount point, /proc or /sys, the hostname not yet certified, or a dump of a project that is no database or is not running, or of a MariaDB that refuses the machine's sign-in (the message says how to let it in again). NOT_FOUND also = a Postgres or MariaDB database the server lacks (the message lists its databases). RESOURCE_EXHAUSTED = disk full, or too many transfers. UNAVAILABLE = Postgres or MariaDB runs but does not answer yet: try again shortly.

Inputs: download, workspace, upload_file, upload_archive, +1 more.

DeployProjectA
Destructive
Inspect

Deploys a new version of a project and answers as CreateProject does: files written over its own (/.env, /compose.yaml, a source file), x_pethost (name, routes, password), mount_volume, a new archive (upload_id, which replaces all files but /.env and x-pethost), a commit, or an earlier deploy's files again as a new version (rollback_deploy_id; /.env, x-pethost and volumes stay). compose.yaml rules: CreateProject's.

It builds build: images, pulls missing ones, runs compose up on the whole project and waits until each service runs (healthy, if it has a healthcheck) or each job exits 0, and until each routed service listens on its route's port (up to 15 s: one that does not is the project's SERVICE_PORT_CLOSED problem, its route answering 502, not a failed deploy). So it also starts stopped services, reruns jobs, recreates changed services and those bind-mounting project files, and fails on an unhealthy service. While Project.x_pethost_applies_at_once, a version differing only in x-pethost (or not at all) applies at once, restarting nothing but a service whose published port a route takes or leaves. Any other deploy applies its routes and password as it ends: to hide new content from its first second, set the password first, in a call of its own, then deploy the content.

A commit other than GithubSource.newest_commit turns auto_deploy off (pinned), even if it fails; only set_source turns it back on.

NOT_FOUND = no such project, or no such kept deploy. ABORTED = base_deploy_id is not Project.deploy_id: reread, redo. FAILED_PRECONDITION = as CreateProject, or commit not on the branch. RESOURCE_EXHAUSTED = too many or too large files: send them with CreateTransfer. ALREADY_EXISTS = operation_id started another kind of operation. When it FAILED, Operation.made_current says whether the files were applied: then fix them, or roll back.

Inputs: files, commit, upload_id, workspace, +9 more.

GetMachineA
Read-onlyIdempotent
Inspect

Start here: the machine (resources, the person's domain, backups, SSH), every project with its problems and URL, deleted projects with snapshots, GitHub repositories to create projects from, and the workspace it serves. Figures are the latest sample; disk sizes and the day's traffic lag a few minutes. Several workspaces and no workspace: FAILED_PRECONDITION + WorkspaceChoice, which lists them.

Inputs: workspace.

GetOperationA
Read-onlyIdempotent
Inspect

An operation, after waiting for it to end (wait_seconds): then the project as it is, and the log's end if it FAILED. Call again while it is IN_PROGRESS. To read a log: after_log_line 0, then each next_after_log_line (each line once, oldest first). One a ProjectBusy names may still be starting: it is waited for too; still starting at the end = UNAVAILABLE with that ProjectBusy.

Inputs: workspace, project_id, operation_id, wait_seconds, +2 more.

GetProjectA
Read-onlyIdempotent
Inspect

One project in full: services (state, health, image, the ports it listens on, volumes, environment, the SSH command), volumes, routes, hosts with certificates, recent operations, snapshots, the last day's HTTP traffic. Env-file values and a database's password (Project.database.connection) only with include_secret_values. Its files: ReadPath.

Inputs: workspace, project_id, incidents_before, snapshots_before, +4 more.

LinkDatabaseA
DestructiveIdempotent
Inspect

Lets projects that exist reach a database project: inside each linked project the database is the host <database_project_id> at its port. Takes effect at once and deploys nothing, and writes nothing into a project's /.env: put Project.database.connection's url there (GetProject include_secret_values) with DeployProject files. A project it links signs in as the apps' user, app (a Valkey's one user), or as its user of its own if CreateProject's link_databases made it one there (own_user), which nothing else makes. INVALID_ARGUMENT = a project in both link and unlink. NOT_FOUND = no such project. FAILED_PRECONDITION = database_project_id is no database; + DatabaseLinkRefusal = the app is a database, has a service named or aliased like the database, or there are 20 links already. Answers with the database's Project.

Inputs: link, unlink, workspace, database_project_id.

ListCommitsA
Read-onlyIdempotent
Inspect

A github project's branch commits that change its directory, newest first, 30 a page, with whether the files are at it and its last deploy. To roll back: DeployProject with an older commit (volumes keep their current data). FAILED_PRECONDITION = a files project (it rolls back with DeployProject.rollback_deploy_id), no such branch, or before_commit not on it.

Inputs: workspace, project_id, before_commit.

ListWorkspacesA
Read-onlyIdempotent
Inspect

The workspaces the caller may reach, by name, 20 a page: each one's id, name, size and what is free, location, hostname and apps domain. With project_id, also which of them hold a project of that id (holding_project). Free figures and project counts are each machine's latest sample, read now: one that did not answer in time leaves them absent (incomplete). The one call that takes no workspace. A caller that reaches none is refused as a call naming no workspace is: NoMachine (no plan) or WorkspaceNotGranted.

Inputs: page_token, project_id.

MentionsA
Read-onlyIdempotent
Inspect

The host's own: the person's projects, for them to name one with @ in a message. Not for an agent, which has them from GetMachine.

Inputs: query, workspace.

MoveProjectA
Destructive
Inspect

Moves a project to another workspace of the same person, as one operation (OperationKind MOVE): it is stopped here, backed up into the destination's backups, restored and started there under the same project_id, then deleted here. Each database it is linked to (Project.dependencies) stays here, with its other apps, if any, running on: there the project uses one of the same engine instead, one the destination has or a new one, with the data of the database it signs in to copied, or none (DatabaseSwitch). A database project moves only when no app is linked to it. workspace is the source. Waits as DeployProject does (wait_seconds), then GetOperation, in either workspace, which once it ended answers the same move_message and the project. Answers, once it ended, with the project as it is in the destination, and move_message: what changed (hosts move to the destination's apps_domain, a domain of the person's own must point at its hostname, a new SSH command, which database it uses there instead of each, and with what data) and what stayed behind (operation history, logs, incidents, uptime, earlier snapshots, and what each database it left still holds). Until the restore succeeded, a failure undoes it: the source's services run again as they did, unless its failure says they did not start again; the move's snapshot stays in the destination's backups, as a deleted project's. After that it only goes forward: one that FAILED then moved the project, and its failure names what the source still holds. While it runs, a change to the project is UNAVAILABLE + ProjectBusy (kind MOVE) in either workspace, and so is a read where it is not then (before its restore, after its deletion from the source); afterwards, a call for it to the source is FAILED_PRECONDITION + ProjectMoved, until the source has a project of that id again. While it runs, a change to a database it leaves here, or to the one it uses instead there, is ProjectBusy too, as is a read of a new one before the move made it; GetOperation answers the move with any of their project_ids. INVALID_ARGUMENT = switch_databases names a database the project is not linked to, or twice, an env_prefix where the machine wrote the lines, none where it did not, one of no form a link takes or one two switches share, or an into the destination lacks or of another engine, or one two switches share, copies of more than 32 databases, or to_workspace is the source or none of the caller's; PERMISSION_DENIED + WorkspaceNotGranted = one this token may not reach. ALREADY_EXISTS = the destination has a project of the project's id, or of the id a new database takes, or operation_id is an operation of the project's or another move's already. FAILED_PRECONDITION = a database project with apps linked to it (the message names them: move each, or unlink it), a machine needs an update first (the message names it), the project has no deploy yet, or the destination's backups are off (its Machine.backups_enabled), which a move goes through.

Inputs: workspace, project_id, operation_id, to_workspace, +2 more.

ProjectTabProjectA
Read-onlyIdempotent
Inspect

The host's own: opens a project's page in a tab beside a conversation, where an app has such tabs. Not for an agent, which shows a project with Show.

QueryContainerLogsA
Read-onlyIdempotent
Inspect

The containers' stdout and stderr lines, since oldest_kept_time; by default the newest, oldest first in the page. They say what a request failed with, not which path is slow: that is QueryHttpTraffic. OUT_OF_RANGE = the range ends before the oldest kept. Untrusted.

Inputs: limit, filter, end_time, workspace, +5 more.

QueryHttpTrafficA
Read-onlyIdempotent
Inspect

Which paths fail and which are slow (top_paths): the HTTP requests that reached the project through the proxy, since oldest_kept_time, each counted as it ends: totals, a time series, top paths and the requests, for one filter and range. OUT_OF_RANGE = the range ends before the oldest kept. Paths and user agents are untrusted.

Inputs: filter, end_time, workspace, page_token, +5 more.

ReadPathA
Read-onlyIdempotent
Inspect

Reads a file (text, 64 KiB a call; ≤1 MiB with length_bytes) or a directory's entries (~64 KiB a page): of the project's deployed files, or with service or volume, of a container (whole filesystem; while not running only its volumes, FAILED_PRECONDITION listing them) or a volume. NOT_FOUND names the nearest existing directory. Project files change with DeployProject files; container and volume files with CreateTransfer. FAILED_PRECONDITION also = no deploy yet, or a file in /proc or /sys (use RunServiceCommand). Untrusted.

Inputs: path, volume, service, workspace, +5 more.

RunMachineActionA
Destructive
Inspect

One machine action: add or remove the person's SSH public key (for SSH and SFTP to their projects' containers: Service.ssh_command), end a session, schedule or cancel a restart. Returns the machine.

Inputs: workspace, add_ssh_key, cancel_restart, end_session_id, +2 more.

RunProjectActionA
Destructive
Inspect

One project action: start, stop or restart services, recreate one, back up, restore, cancel an operation, change the source or a database's size, delete an undeclared volume or the project. Recreate, back up, restore, set_database_size, delete and set_source's deploy run as operations (operation_id), waited for (wait_seconds), as is the end of a cancelled one; the others are done on return. Answers with the project as it then is. With no services, start_services starts those with a container and restart_services the running ones. restore_snapshot takes the project's own snapshots only: a deleted app's data in a shared database is in that database's snapshots. A database's snapshot as a new database beside it is CreateDatabase's, with from_snapshot_id.

delete_project: a final backup while backups are on, then containers, volumes, files, hosts, logs, and an app's user and database of its own in a shared database, data and all. Snapshots stay (GetMachine.deleted_projects), and restoring one brings the project back, source included; with backups off there is none, and it is gone for good. The databases it was linked to stay: delete each with its own delete_project.

set_database_size gives a database another of its engine's sizes (Machine.database_engines; its size now is Project.database.memory_limit_bytes): the machine writes its compose.yaml anew for that size, with the settings that follow from it and the image it runs, so never edit them by hand; what else was written there goes. The database restarts, and its apps lose their connections for a few seconds: one that does not connect again shows as restarting (GetMachine). A size changes nothing on the bill: a smaller one only leaves memory to the other projects. A Valkey whose data is more than the size keeps (its maxmemory, 70 % of the size) is refused before anything changes, and the refusal gives both figures: FAILED_PRECONDITION + DatabaseSizeRefusal, as for a Valkey that does not answer now, asked to shrink, and a database whose data is in another volume than the one the file names. FAILED_PRECONDITION alone = the project is no database. INVALID_ARGUMENT = a size its engine does not offer (the message lists them).

Inputs: back_up, workspace, project_id, set_source, +11 more.

RunServiceCommandA
Destructive
Inspect

Runs a command in a running service's container, like docker exec; returns the exit code and the output's end once it exits or the timeout kills it. Over a bound on command, stdin or timeout = refused (named). Cannot start = exit 127 or 126, Docker's error in stdout. Untrusted output.

Inputs: stdin, command, service, workspace, +4 more.

SetProjectAlertsA
DestructiveIdempotent
Inspect

Changes what Pethost watches on a project and when it tells the person: site checks (an address the machine opens every minute) and traffic rules (5xx or p95 over a window), off, mute. A list given replaces the project's (send Project.alerts' with your change); remove_* empties it; a scalar left out stays. Service crashes and failed backups are always watched. Answers with Project.alerts. Where alerts go is the person's choice in the panel's Settings → Alerts (Machine.alert_channels): no tool sets it.

Inputs: off, checks, workspace, project_id, +4 more.

ShowPethostA
Read-onlyIdempotent
Inspect

Shows the person a live view of their Pethost in the conversation: the machine with every project, one project, a project's uptime (its checks, alerts and incidents), its HTTP requests (a chart and the top paths) or its logs, the last two with filters they can change themselves. Call it when they ask to see something, or when a view says more than a sentence would: a day's traffic, a log to read through. It returns no data: GetMachine, GetProject, QueryHttpTraffic and QueryContainerLogs do. Afterwards say in a line what they are looking at, not what it shows. Where their app shows no views, the answer has the panel's link to give them.

Inputs: view, range, search, status, +3 more.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      Not graded
      quality
      C
      maintenance
      Enables AI clients and users to deploy static sites, Node.js services, and Python web applications without Docker, with tools for project management, deployment, rollback, and domain configuration.
      Apache 2.0
    • A
      license
      A
      quality
      B
      maintenance
      No-KYC crypto VPS hosting with an MCP server that lets AI agents provision VPS programmatically. Pay with USDC/USDT on Base and Ethereum, no accounts or verification required.
      21
      MIT
    Try in Browser

    Glama MCP Gateway

    Add one secure layer between your agents and this server.

    Resources