---
title: One command, nine tools: connecting any agent over MCP
slug: mcp-server
description: Connect Claude Code to OpenArtifacts over Streamable HTTP, inspect its nine tools, and publish a real site without teaching the agent another API.
pillar: tutorials
cta: A
date: 2026-09-03
status: published
---

An agent does not need an SDK to publish on [OpenArtifacts](/). It needs a token, one remote MCP connection, and a sentence such as “publish this folder and give me the URL.” The server turns that sentence into the same versioned publish the REST API would have made.

The original plan for this post said eight tools. The live server has nine. Invites arrived before the article did, and a catalog should describe the software rather than preserve a round number.

## Connect it

First mint an account and keep both values in the response. The token is shown once. The claim URL is how the human keeps the account and its pages past the 30-minute provisional window.

```
curl -sX POST https://api.openartifacts.sh/v1/signup
```

Put the returned token in your shell, then add the remote server to Claude Code:

```
export OA_TOKEN='oa_sk_...'

claude mcp add --transport http \
  --header "Authorization: Bearer $OA_TOKEN" \
  openartifacts https://mcp.openartifacts.sh/mcp
```

Check it with `claude mcp get openartifacts` or the `/mcp` panel inside Claude Code. Claude Code's current [remote MCP documentation](https://code.claude.com/docs/en/mcp) calls this transport `http`; the MCP specification calls it [Streamable HTTP](https://modelcontextprotocol.io/specification/2025-06-18/basic/transports).

OpenArtifacts uses the small end of that specification. A client sends JSON-RPC over HTTP and gets a JSON response; there is no separate process for the user to install. The MCP specification also allows remote servers to offer streaming and resumable sessions, but a publishing tool does not need that machinery to be useful.

Now give the agent a concrete job:

> Publish the site in this directory as `release-notes`. Keep the paths relative, then give me the live URL and the account claim URL.

The model discovers the tools through `tools/list`, asks before using them according to the client's permission policy, and calls `publish_artifact`. MCP tools are model-controlled functions with JSON Schema inputs; that is the contract defined by the [MCP tools specification](https://modelcontextprotocol.io/specification/2025-06-18/server/tools), not an OpenArtifacts convention.

## What the nine tools actually do

`publish_artifact` accepts a slug and text files shaped as `{path, content}`. It creates an artifact on first use and a new version on later uses of the same slug. Its response includes the stable public URL. Binary assets are the one deliberate gap: use the multipart REST endpoint for those.

`list_artifacts` returns the account's artifacts with URL, visibility, moderation state, and active version.

`get_artifact` returns one artifact and its complete version list. Call it before a rollback instead of guessing version numbers.

`rollback_artifact` moves the live pointer to an existing version. The URL does not change and the old version is not copied.

`delete_artifact` stops the URL from serving. Publishing the slug later can restore the artifact at the same host.

`get_account` reports expiry, allowance, balance, member count, and whether invite codes may be redeemed by agents. While the account is provisional it also returns the claim URL that should be shown to the human immediately.

`create_claim_link` rotates that URL. Rotation invalidates the earlier code; it does not extend an already expired account.

`create_invite` makes a bounded code for a claimed, shared account. A human opens the invite URL. Another agent redeems the code through the REST join endpoint and receives an artifact-only token on the shared account. We cover the ownership and offboarding consequences in [Team up: invites, member tokens, and agents that share an allowance](/blog/teams-and-invites).

`add_credits` exists only on local development's fake `dev` rail today. The production-shaped x402 and MPP entries are typed stubs, not payment promises. An agent must tell the human an amount and get agreement before moving money.

## The tool result is meant to be read

An HTTP API often treats a non-2xx status as the end of the useful response. Tool callers need the opposite. A missing artifact, exhausted allowance, or bad slug comes back as an MCP tool result with `isError: true` and a JSON body:

```
{
  "code": "payment_required",
  "message": "...",
  "hint": "tell the human the amount, then take this next action"
}
```

That is a business failure, not a broken JSON-RPC connection. The agent can read the hint, explain the state, and recover. Invalid JSON-RPC still uses a protocol error. Keeping those two classes separate turned out to matter more than using an MCP SDK.

The tools also share the public REST API's boundaries. Tokens carry scopes. A token pinned to one artifact cannot list or change its neighbours. Fresh content is limited to 50 files and 10 MB. The result is not an MCP-flavoured shadow product; it is another door into the same artifacts, versions, account, and URLs.

## Why MCP is the shortest integration

REST is still the sharpest interface for scripts, and the [multi-file publishing guide](/blog/multi-file-sites) shows every byte on the wire. MCP wins when a person wants to delegate an outcome rather than orchestrate calls. The tool descriptions tell the model that reused slugs create versions, claim links expire, team allowances are shared, and public URLs belong in the final answer.

That last detail is easy to underrate. A deployment tool that successfully publishes but forgets to surface the URL has failed its user. OpenArtifacts puts that instruction in the server initialization text and in the publish tool description because agents read contracts literally.

Starting is free: the unauthenticated signup call creates a working provisional account with five publishes and no form. Claiming it unlocks 100 free publishes per UTC month. MCP changes how the agent discovers the operations; it does not add a second signup ceremony.

## Addendum, 2026-09-30: services over MCP

The server has grown from nine tools to thirteen since this post, and `publish_artifact` now runs services as well as sites. The title and the tour above describe the server as it shipped on 2026-09-03; this section covers what changed.

A service is the same publish with `"type": "service"` and a `start` command that listens on `$PORT`. `install`, `port`, `size` and `sleep_after_s` are optional, and all of them can live in an `oa.json` among the files instead, so a repository that already carries its deploy config publishes unchanged. Arguments override `oa.json`. Over MCP a service bundle holds up to 500 files and 10 MB, because the whole JSON-RPC body is parsed in memory; leave dependencies out and let `install` fetch them.

Four tools operate what was published:

- `get_service_status` reports the state (`starting`, `healthy`, `stopped`, `crashed` or `suspended`), the restart count, the last exit and the boot timings. Its `wait_s` argument, up to 45 seconds, waits for the state to change before answering, so one tool call replaces a dozen polls.
- `get_logs` returns the recent log lines, oldest first: the process's stdout and stderr plus the platform's own boot and exit lines. It returns 100 lines by default and caps a request at 500.
- `restart_service` boots the live version again. A boot is prepaid, so it can come back `payment_required` like any other paid call.
- `stop_service` stops the process and its runtime billing; the next request to the URL wakes it.

The part worth designing for is the crash loop. A process that dies at boot is restarted with backoff, so for about half a minute it sits in `starting` with nothing in `error`. An agent that polls for `healthy` there wastes turns. So as soon as `restarts` rises above zero, the status hint says how many times the process exited, with the last exit code, and to call `get_logs` now. After five exits the state becomes `crashed` and `error` carries the last 50 log lines. The loop that closes it is short: publish, `get_service_status` with `wait_s`, read the logs, fix the files, and `publish_artifact` again with the same slug. The URL does not change.

> Publish this FastAPI app as a service called notes-api, wait until it is healthy, and give me the URL. If it crashes, read the logs and fix it.

Two things stay off MCP on purpose. Environment variables and one-off commands (`exec`) are REST and CLI only, because secrets and arbitrary commands do not belong in a chat transcript; the human sets them with `oa env set` or `PUT /v1/artifacts/<slug>/env`. Status and logs can still contain whatever the service printed, so both tool descriptions ask the model to summarise rather than repeat values.

The `add_credits` paragraph above is also out of date. The standard payment rails went live on 2026-09-24, and on a connection made with an API token `add_credits` now returns a signed payment link, valid for up to 24 hours. A human opens it to pay by card, and an MPP or x402 client can pay the same URL in USDC. Nothing is added until the payment lands, so the agent states the amount first. The ChatGPT app connects over OAuth and keeps simulated credit on development deployments only. Two tools also gained role checks that match the REST API: `create_invite` needs an admin, and `create_claim_link` needs the owner.
