# MCP Server Setup

CurlyFlies ships a hosted [Model Context Protocol](https://modelcontextprotocol.io) server. Connect it once and your agent sees `upload_file` as a native tool — it will host files mid-task without being told, with no integration code and no developer wiring.

## Connection details

| | |
|---|---|
| Server URL | `https://mcp.curlyflies.com/mcp` |
| Transport | Streamable HTTP |
| Auth | Bearer token in the `Authorization` header (your CurlyFlies API key) |

Get a key from the [dashboard](https://curlyflies.com/dashboard) or via agent self-provisioning (`POST /v1/agent/signup` — see the [API reference](/docs/api.md#agent-signup)).

## Setup by client

### Claude Desktop

Edit `claude_desktop_config.json` (macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`):

```json
{
  "mcpServers": {
    "curlyflies": {
      "url": "https://mcp.curlyflies.com/mcp",
      "apiKey": "curly_live_abc123"
    }
  }
}
```

Restart Claude Desktop. The four CurlyFlies tools appear in the tool list.

### Cursor

Add to `.cursor/mcp.json` in your project (or `~/.cursor/mcp.json` globally):

```json
{
  "mcpServers": {
    "curlyflies": {
      "url": "https://mcp.curlyflies.com/mcp",
      "headers": {
        "Authorization": "Bearer curly_live_abc123"
      }
    }
  }
}
```

### Any other MCP client

Point a Streamable HTTP transport at `https://mcp.curlyflies.com/mcp` and send `Authorization: Bearer {api_key}` on every request.

## The four tools

### `upload_file`

Upload bytes (base64) and get a public URL back.

Parameters:

| Name | Type | Default | |
|---|---|---|---|
| `content_base64` | string | — | required |
| `filename` | string | `"file"` | |
| `content_type` | string | auto-detected | |
| `ttl_seconds` | integer | `86400` | |

Returns: `{ url, expires_at, file_id, size_bytes }`

Agents use this whenever they need to: host a generated image so Instagram, Buffer, or Meta Ads can fetch it; get a public URL for any downstream API; or share a file between agent steps without a shared filesystem. The returned URL works immediately, requires no authentication, and passes Instagram's URL validation.

### `upload_from_url`

Fetch a file from a remote URL and re-host it on CurlyFlies.

Parameters:

| Name | Type | Default | |
|---|---|---|---|
| `url` | string | — | required |
| `ttl_seconds` | integer | `86400` | |

Returns: `{ url, expires_at, file_id, size_bytes }`

Use when you have an image URL from GPT Image (OpenAI), Nano Banana (Google), Seedream, Flux, Midjourney, Replicate, Higgsfield, or any source with auth requirements, redirects, or expiring signed URLs that downstream APIs cannot access.

### `get_file_info`

Check if a previously uploaded file is still live.

Parameters: `file_id` (string, required)

Returns: `{ exists, url, expires_at, file_id }` — or `{ exists: false }` if expired.

Use before passing a URL to a downstream API if time has passed since the upload.

### `delete_file`

Delete a file before it expires naturally.

Parameters: `file_id` (string, required)

Returns: `{ deleted: true, file_id }`

Use for cleanup after a downstream API has successfully processed the file, or when a workflow fails and temp files should be removed.

## A typical autonomous flow

1. Agent generates an image with an image model — gets back a signed URL that expires in 60 seconds.
2. Agent calls `upload_from_url` with that URL — gets back a stable curlyflies URL valid for 24h.
3. Agent posts the curlyflies URL to the Instagram Graph API — accepted, no error 9004.
4. Agent calls `delete_file` once the post is confirmed.

No step required a human, a bucket, or an OAuth flow.

## Troubleshooting

- **Tools don't appear** — restart the client after editing config; verify the JSON is valid.
- **`401` from the server** — the API key is wrong, regenerated, or in the wrong place. It must be a Bearer token in the `Authorization` header (some clients use an `apiKey` field that maps to it).
- **`429`** — you hit your plan's hourly rate limit. The response includes `Retry-After`.
- **Test the connection** — the dashboard's **MCP Setup** tab has a one-click connection test, or call `get_file_info` on any file id and confirm you get a JSON response (a `404` still proves connectivity).
