# Linkdash MCP

Remote MCP at `https://api.linkdash.dev/mcp`.

Auth: `Authorization: Bearer ldash_...` (create keys at https://linkdash.dev/dashboard/keys). Same Unkey keys as the [HTTP API](https://linkdash.dev/api.md). Device login (`auth create` / `auth login`) is CLI-only. Do not invent keys.

Tools match CLI stdout JSON. Markdown reference: [api.md](https://linkdash.dev/api.md). CLI: [cli.md](https://linkdash.dev/cli.md). Pricing: [pricing.md](https://linkdash.dev/pricing.md).

## Connect

Key from [dashboard/keys](https://linkdash.dev/dashboard/keys).

**Cursor** (`~/.cursor/mcp.json` or `.cursor/mcp.json`):

```json
{
  "mcpServers": {
    "linkdash": {
      "url": "https://api.linkdash.dev/mcp",
      "headers": { "Authorization": "Bearer ${env:LINKDASH_API_KEY}" }
    }
  }
}
```

**Claude Code:**

```bash
claude mcp add --transport http linkdash https://api.linkdash.dev/mcp --header "Authorization: Bearer $LINKDASH_API_KEY"
```

JSON config uses `"type": "http"`.

**Codex:**

```bash
codex mcp add linkdash --url https://api.linkdash.dev/mcp --bearer-token-env-var LINKDASH_API_KEY
```

**OpenCode:**

```bash
opencode mcp add linkdash --url https://api.linkdash.dev/mcp --header Authorization="Bearer $LINKDASH_API_KEY"
```

Local: Convex `.site` URL + `/mcp`, same bearer header.

## Tools

| CLI | HTTP | MCP |
| --- | --- | --- |
| `auth whoami` | `GET /v1/me` | `whoami` |
| `links list` | `GET /v1/links` | `links_list` |
| `links get <id>` | `GET /v1/links/:id` | `links_get` |
| `links create` | `POST /v1/links` | `links_create` |
| `links update <id>` | `PATCH /v1/links/:id` | `links_update` |
| `links delete` | `DELETE /v1/links/:id` | `links_delete` |
| `links stats` | `GET /v1/links/:id/stats` | `links_stats` |
| `links export` | `GET /v1/links/export` | `links_export` |
| `links import` | `POST /v1/links/import` | `links_import` |
| (host PUT after mint) | `POST /v1/uploads` | `files_upload_url` |
| | `DELETE /v1/uploads` | `files_discard` |
| `webhooks list/create/get/rotate/delete` | `GET/POST /v1/webhooks`, `GET/DELETE /v1/webhooks/:id`, `POST /v1/webhooks/:id/rotate` | `webhooks_*` |
| `domains list/add/connect/verify/remove` | `GET/POST /v1/domains`, `GET /v1/domains/:host/connect` | `domains_*` |

`auth create`, `auth login`, and `auth logout` are not MCP tools.

`links_create` takes exactly one of `url`, `text`, or `storageId` (plus `fileName`, `fileType`, `fileSize`). Optional on any kind: `slug`, `name`, `tags`, `starts`, `expires`, `maxOpenings`, `password`, `domain`, `previewName`, `previewDescription`, `previewImageStorageId`, `utm` (URL only). `links_update` also takes `clearMaxOpenings`. After `maxOpenings` is reached the link pauses; raise the number or clear it to serve again.

## Files

Do not send file bytes through MCP JSON. Mint a URL (`{uploadUrl,storageId}`), PUT the file from the host, then create the link in the same flow:

```bash
curl https://api.linkdash.dev/v1/uploads \
  -H "Authorization: Bearer ldash_..." \
  -H "Content-Type: application/json" \
  -d '{"fileSize":12345}'

curl -X PUT -H "Content-Type: video/mp4" --data-binary @clip.mp4 "$uploadUrl"

curl https://api.linkdash.dev/v1/links \
  -H "Authorization: Bearer ldash_..." \
  -H "Content-Type: application/json" \
  -d '{"storageId":"…","fileName":"clip.mp4","fileType":"video/mp4","fileSize":12345}'
```

MCP: `files_upload_url` returns `{uploadUrl,storageId}` → host PUTs to `uploadUrl` → `links_create` with that `storageId`. The host (runtime / curl) PUTs the bytes, not the model. Do not print `uploadUrl` back to the user. A preview image uses the same upload then `previewImageStorageId` on create.

## Agent rules

1. Use only the tools in this file. Do not invent OAuth or device-login MCP auth.
2. Never put secrets in examples you echo back.
3. After adding a CLI verb that talks to Linkdash, add `/v1` and an MCP tool in the same change.
