# Docs

> An agent reaches permahost.io in two ways: the `file` tool of the MCP server, or the `permahost` CLI. Both upload, download, list and link files in folders that stay up until they are deleted.

HTML version: https://permahost.io/docs/

- [**MCP tool**: The `file` tool at https://mcp.permahost.io/mcp and its actions `upload`, `download`, `get`, `url` and `list`, with example calls and results.](https://permahost.io/docs/mcp.md)
- [**CLI**: The `permahost` command: install, sign in, upload a file or a whole directory, add a domain.](https://permahost.io/docs/cli.md)
- [**curl**: For when the CLI can't be installed: the HTTP API with curl and a Bearer token.](https://permahost.io/docs/api.md)
- [**Custom domains**: Serve a folder on your own hostname: add it, create the CNAME record, verify, get HTTPS.](https://permahost.io/docs/domains.md)
- [**Plugins**: Add permahost.io to Claude Code, Codex, Cursor or Gemini CLI: the MCP server plus instructions on when and how to publish files.](https://permahost.io/docs/plugins.md)

## CLI or MCP?

Guideline

**If the agent can run shell commands, use the CLI.** `permahost file upload` reads files from local paths and prints only their URLs, and `permahost file download -o` writes to a local path, so a 5 MB PDF or a whole `dist/` folder costs the context a few lines. Through MCP, every byte of a file is a tool argument the model has to write out, and every byte of a download comes back into its context.

**Without a shell, use MCP, and send text as text.** For `.html`, `.css`, `.js`, `.md`, `.json`, `.svg` and other UTF-8 files, pass `format: "textContent"`: the content goes as is. The default, `base64Content`, makes the payload a third larger and turns readable text into opaque characters. Keep `base64Content` for binary files such as images and PDFs.

| Way | What passes through the model's context | Use it for |
| --- | --- | --- |
| CLI | The command, then the folder id and URLs | Any file, any size, whole directories |
| MCP textContent | The file's text, as is | Small text files the agent just wrote: HTML, CSS, JS, Markdown, JSON |
| MCP base64Content | The file as base64: 4 characters for every 3 bytes | Small binary files, when there is no shell |

### The same upload, both ways

A 300 KB `report.html` through the CLI is one short command:

Shell:

```
$ permahost file upload report.html
```

Through MCP, the same file is 300 KB of `textContent` in the tool call, or about 400 KB as `base64Content`. Either way the model writes it out token by token.

## Concepts

### Folders

Every upload goes into a folder. A folder of a signed-in account never expires: it stays up until you delete it, as long as the account has credits. An upload without a folder id creates a new folder; an upload with one adds to that folder.

**Reuse folders.** Each new folder costs credits every month, while adding files to an existing one never does. To publish a site, upload the first file without an id, keep the `id` it returns, and pass it for every other file. To add to something published earlier, find its folder with the MCP `list` action or `permahost file ls`.

### Folder ids and URLs

An upload returns the folder's `id`, 11 random lowercase letters and digits (such as `k7q2m9xa3bd`), and the file's public `url` (such as `https://k7q2m9xa3bd.file.permahost.io/index.html`). The folder URL serves a page when `index.html` sits at its root. Take URLs from the responses instead of building them by hand.

### Paths

A file can live in directories inside its folder (`path`, such as `site/css`), at most 5 levels deep. Paths use `/`, with no `.` or `..` segments and no backslashes.

### Updates

Uploading to a path that already holds a file replaces it in place: its URL stays the same, and only the size difference counts toward storage.

### Custom domains

A folder can also be served on hostnames you own, such as `www.example.com`, through a CNAME record. See [custom domains](https://permahost.io/docs/domains/).

### Sign-in

Sign in with Google or GitHub. Both the MCP server and the CLI sign in with OAuth through app.permahost.io in the browser, once. The CLI saves its tokens and refreshes them; MCP clients that support OAuth do the same. With [curl](https://permahost.io/docs/api/), send the access token as a Bearer token.

## Credits

Hosting is paid for with credits, by the month. Every account gets a monthly credit grant; each cost is charged upfront when it starts, and each renewal charges the next month for everything the account hosts then.

| What | Credits | Charged |
| --- | --- | --- |
| Folder | 500 a month | When it is created. Adding or replacing files in it never costs folder credits again. |
| Storage | 500 a month per started 25 MB the account stores | When an upload pushes the account's total into a block not yet paid for this month, so most uploads cost 0. |
| Custom domain | 500 setup + 500 a month | When its CNAME record is verified. |

Unused credits do not carry over: each renewal resets the balance to the grant minus the coming month's hosting cost. If that leaves the balance below zero, every site of the account is paused (HTTP 402) until a later renewal brings it back to zero or above. Nothing is deleted. `permahost whoami` shows the balance, the renewal time, what the account hosts and its monthly cost.
