---
url: /developers
title: Publish HTML from Code – Agent, API, MCP and CI
updatedAt: "2026-10-16"
description: "Four ways to publish HTML and Markdown from code: an agent request, the REST API, the MCP server and a CI step. All four update the same URL and set who can open it."
---

# Publish HTML from an agent, the API, MCP or CI.

Each surface publishes HTML or Markdown to a URL, updates it at the same URL, and sets who can open it. Viewers are unlimited on every plan.

[Get an API key free →](https://app.display.dev) · [Read the docs](/docs)

---

## How do I publish HTML from code?

Use the surface that matches who runs it. A person or an agent on a machine asks the agent to publish the file to Display (display.dev), the docs workspace for agents and people. A service in another language sends a multipart `POST` to `https://api.display.dev/v1/artifacts`. An agent that has the MCP server calls its `publish` tool. A build job asks an agent step, or calls the REST API, with an API key in a secret. All four publish HTML or Markdown to a URL. All four update it at the same URL with the version you edited from, and set who can open it.

---

## Four surfaces, one request each

| Surface  | Use it when                    | One request                                                                                                             |
| -------- | ------------------------------ | ----------------------------------------------------------------------------------------------------------------------- |
| Agent    | You or a script publish a file | "Publish report.html to Display for my company"                                                                         |
| REST API | Your own service publishes     | `curl -X POST https://api.display.dev/v1/artifacts -H "Authorization: Bearer $DISPLAYDEV_API_KEY" -F file=@report.html` |
| MCP      | An agent publishes             | Call the `publish` tool at `https://api.display.dev/v1/mcp`                                                             |
| CI       | Every merge updates a page     | Run an agent step, or call the REST API, with the current version                                                       |

Each call returns a URL and a short ID. Each update needs the version you edited from, so one writer cannot overwrite another by mistake.

---

## Agent

Connect Display to your agent once. Then ask in plain words:

> Publish report.html to Display for everyone at my company.

> Update the Display page at the same link with the new numbers.

> Read the open comments on that page, fix them and resolve the threads.

A signed-in publish starts as Private. Say who can open it in the request: public, company, or named email addresses. With no sign-in and no API key, the agent can publish a public preview that stays for 30 days, with a claim URL. Agents with a shell use the `dsp` command-line tool. The [CLI reference](/docs/cli-reference) lists the commands.

---

## REST API

Create an API key in the dashboard. The API takes a multipart form with a `file` field. The optional fields are `name`, `visibility` and `theme`.

```bash
# Publish
curl -X POST https://api.display.dev/v1/artifacts \
  -H "Authorization: Bearer $DISPLAYDEV_API_KEY" \
  -F file=@report.html \
  -F name="Q3 review" \
  -F visibility=company

# Update the same URL. If-Match carries the version you edited from.
curl -X PUT https://api.display.dev/v1/artifacts/abc123 \
  -H "Authorization: Bearer $DISPLAYDEV_API_KEY" \
  -H 'If-Match: "v5"' \
  -F file=@report.html
```

The response holds `url`, `shortId`, `version` and `name`. A stale version returns `412`. A missing `If-Match` header returns `428`. Without a key, `POST https://api.display.dev/v1/public/artifacts` publishes a public preview that stays for 30 days.

---

## MCP

The server has tools for publishing, reading, search, sharing, comments and organization work. The [MCP tools reference](/docs/mcp-server) lists them. Connect from Claude's connector directory, or add the endpoint to your client. When the MCP `publish` tool updates a page, it takes a `base_version` field.

```bash
claude mcp add --transport http --scope user display https://api.display.dev/v1/mcp
```

```toml
# ~/.codex/config.toml
[mcp_servers.display]
url = "https://api.display.dev/v1/mcp"
bearer_token_env_var = "DISPLAYDEV_API_KEY"
```

Cursor supports OAuth for remote servers. Add the endpoint as a `url` entry in `~/.cursor/mcp.json` and sign in from **Settings → MCP**. Each agent has a setup guide: [Cursor](/docs/mcp-cursor), [Codex](/docs/mcp-codex), [Claude Code](/docs/mcp-claude-code) and [ChatGPT](/docs/mcp-chatgpt).

---

## CI

Store the API key as a secret and the artifact's short ID as a variable. Each merge then updates the page at the same URL. The step reads the current version, then sends a `PUT` with that version in `If-Match`.

```yaml
- run: |
    V=$(curl -s -H "Authorization: Bearer $DISPLAYDEV_API_KEY" \
      "https://api.display.dev/v1/artifacts/${{ vars.DISPLAY_ARTIFACT_ID }}/metadata" | jq -r .currentVersion)
    curl -X PUT "https://api.display.dev/v1/artifacts/${{ vars.DISPLAY_ARTIFACT_ID }}" \
      -H "Authorization: Bearer $DISPLAYDEV_API_KEY" \
      -H "If-Match: \"v$V\"" \
      -F file=@dist/report.html
  env:
    DISPLAYDEV_API_KEY: ${{ secrets.DISPLAYDEV_API_KEY }}
```

An agent step can do the same work. [Publish from CI/CD](/docs/ci-cd) has the full workflow and a GitLab version.

---

## Credentials and what they can do

**User key or OAuth sign-in.** The call acts with that person's role. A publish starts as Private.

**Organization service key.** The call can work with Public and Company artifacts, not Private ones. A publish starts as Company. Use this key for CI.

**Scoped keys.** Pro and Enterprise can limit what a key can do.

**Key creation.** Create keys in the dashboard. The CLI does not create keys.

**Organization policy.** The policy applies to every surface. An Owner can restrict Public artifacts or outside sharing for the whole organization. A call that asks for a restricted audience then fails.

---

## Limits

- Today Display takes one HTML or Markdown file for each artifact. Folders are planned. Build to one file, or deploy the folder to a static host.
- A file can be 10MB on Free and 50MB on paid plans.
- A remote MCP call sends content inline or through a staged file transfer (`create_upload`, then `publish` with `upload_id`).
- Outside guests can view an artifact but cannot comment yet.

---

## When another tool is better

Use a static host or an app platform when the output is a site with many files, a server or a database. Wrangler, for example, deploys a folder to Cloudflare. Use Display when the output is a document that people review: a report, a specification, a diagram, a dashboard or a prototype in one file. If your readers are engineers only and the content is public, a site that builds from a repository can be enough. The [software engineers page](/software-engineers) shows how teams use Display with Cursor, Codex and Claude Code.

---

## FAQ

**How do I publish HTML from code?**

Ask your agent to publish the file to Display, send a multipart `POST` to `https://api.display.dev/v1/artifacts`, call the MCP `publish` tool, or run a CI step. Each returns a URL.

**How do I update a page and keep its URL?**

Tell your agent to update the page at the same link. In the API, send a `PUT` with a multipart `file` and the header `If-Match: "v<version>"`. In the MCP `publish` tool, send `short_id` and `base_version`.

**Do I need an account to try it?**

No. Without a sign-in, the API and the public MCP endpoint publish a public preview that stays for 30 days. Open the claim URL and sign in to keep it.

**Which agents work with the MCP server?**

Cursor, Codex, Claude Code, ChatGPT and any client that supports remote MCP servers. Claude has a listing in its connector directory.

**Can CI publish a folder of build output?**

Not today. Display takes one HTML or Markdown file for each artifact. Folders are planned. A CI step can publish one built file.

**Who can open what I publish?**

You choose for each artifact: public, everyone at your company, private, or named email addresses. Every plan supports a one-time password (OTP) sent by email. Pro and Enterprise add Google and Microsoft sign-in. Viewers are unlimited.

**What does it cost?**

Free is €0 with 3 gated artifacts and unlimited public ones. Solo is €15 a month, Pro is €49 a month and Enterprise starts at €499 a month. No plan charges for each viewer. See [pricing](/pricing).
