# Kuailian MCP Server

Publish AI-generated web pages to a live, shareable URL — straight from Cursor, Claude Code, or any MCP client.

[中文文档](./README.zh-CN.md) · [kuailian (快链)](https://link.3ceng.cn)

Ask your agent to *"build a landing page and put it online"* and it comes back with `https://link.3ceng.cn/view/a1b2c3d4`. No git repo, no build pipeline, no deploy config.

> Kuailian is a Chinese-language hosting service. Account registration currently requires a mainland-China mobile number.

## Setup

1. Sign in at [link.3ceng.cn](https://link.3ceng.cn), open the **MCP** tab, and generate an API key.
2. Add the snippet below to your MCP client config (`mcp.json` for Cursor). The key is shown only once — store it somewhere safe.

```json
{
  "mcpServers": {
    "kuailian": {
      "command": "npx",
      "args": ["-y", "@kuailian/mcp-server"],
      "env": {
        "KUAILIAN_API_KEY": "kl_live_xxx"
      }
    }
  }
}
```

Nothing to install and no service to keep running — your client spawns the server as a child process on demand over stdio and shuts it down afterwards. Publishing itself calls the Kuailian API, so an internet connection is required.

### Environment variables

| Variable | Required | Default |
|----------|----------|---------|
| `KUAILIAN_API_KEY` | yes | — |
| `KUAILIAN_API_URL` | no | `https://link.3ceng.cn/api` |
| `KUAILIAN_SITE_URL` | no | `https://link.3ceng.cn` |

## Tools

| Tool | What it does |
|------|--------------|
| `kuailian_publish_html` | Create and publish a page from `html` / `css` / `js` |
| `kuailian_update_page` | Update an existing code page (partial updates are safe) |
| `kuailian_publish_dir` | Zip and publish a local static directory such as `dist/` |
| `kuailian_update_dir` | Overwrite a folder site from a local directory |
| `kuailian_get_task` | Wait for a long-running `publish_dir` / `update_dir` upload |
| `kuailian_list_pages` | List your sites with view counts and origin |
| `kuailian_get_page` | Fetch one project's details and source |
| `kuailian_delete_page` | Move a project to trash |
| `kuailian_get_quota` | Check membership status and remaining quota |
| `kuailian_get_stats` | Traffic stats for a short link (paid feature) |
| `kuailian_check_slug` | Check custom `name.sites.3ceng.cn` availability (paid) |
| `kuailian_set_site_slug` | Set or clear custom subdomain (paid) |

Publish tools accept optional `slug` (paid). Responses include `url` (`/view/{shortId}`) and `share_url` / `custom_url` when a slug is set.

### Examples

**Single page.** `kuailian_publish_html` takes `name` plus any of `html`, `css`, `js`. Pass a full HTML document or just body markup. The whole request body is capped at 2 MB; beyond that you get `CODE_SIZE_EXCEEDED` and should switch to `kuailian_publish_dir`.

**Partial updates.** `kuailian_update_page` merges rather than replaces. Sending only `js` leaves the existing `html` and `css` untouched, so an agent iterating on one part of a page can't accidentally blank the rest.

**Static build output.** `kuailian_publish_dir` takes a `path` to a directory containing `index.html`; `node_modules` and `.git` are skipped automatically. Large directories often take more than a minute to upload, longer than an MCP client waits for one call. If the upload isn't finished after about 20 seconds, the tool returns `status: "running"` with a `task_id`; call `kuailian_get_task` to wait for the outcome instead of uploading again. `kuailian_update_dir` also returns a `baseline` (the site's `updated_at` and `version` before the upload); if the task is lost because the MCP server restarted, compare it with `kuailian_get_page` to tell whether the update landed. After an update the server refreshes the CDN cache for up to about 60 files per upload, within a daily account quota; anything it couldn't refresh is listed in `warnings`. When the directory has `index.html` at its root and no `package.json`, the tools hash every file, upload only the files whose content changed straight to storage (`method: "direct"`), and report the counts in `upload_stats`; this path has no request-size cap. Anything else (a source project, a wrapper folder) is sent as one zip (`method: "zip"`), which is rejected above about 10 MB after compression with `CDN_BODY_TOO_LARGE`. Files you delete locally are not removed from the live site.

## Resources

The server also exposes reference documents your agent can read before acting:

- `kuailian://docs/limits` — size and quota limits
- `kuailian://docs/kv-api` — the key-value API available to published pages
- `kuailian://docs/publish-guide` — how to choose between the publish tools

## Errors and quotas

Failures come back as structured errors with a machine-readable code, so an agent can react instead of retrying blindly:

| Code | Meaning |
|------|---------|
| `CODE_SIZE_EXCEEDED` | Request body over 2 MB — use `kuailian_publish_dir` |
| `QUOTA_EXCEEDED` | Site or traffic quota used up |
| `FEATURE_LOCKED` | Paid-only feature; includes an `upgrade_url` |
| `NOT_MCP_PROJECT` | Site was created in the web app; delete it there instead |
| `INVALID_ID` | `project_id` is not a 24-character hex string |

An API key can create, read, and update sites, but it may only **delete** sites that were created through MCP. Anything a user made by hand in the web app is off limits, which keeps an over-eager agent from destroying work it didn't create. Upgrades always happen in the browser — MCP cannot make a payment on the user's behalf.

## Development

```bash
cd mcp-server && npm i && npm run dev
```

To point a client at your working copy, set `command` to `npx` and `args` to `["-y", "tsx", "<absolute path to mcp-server/src/index.ts>"]`, then override `KUAILIAN_API_URL` and `KUAILIAN_SITE_URL` to your local server.

## License

MIT
