> For the complete documentation index, see [llms.txt](https://docs.kinesis.network/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.kinesis.network/mcp/tools/domains.md).

# Custom domains

Reserve and verify DNS, attach custom domains and choose the default address.

Reserve and verify DNS, attach custom domains and choose the default address.

These are action names. In default compact mode, call the indicated group tool with `{"action":"<action-name>","params":{...}}`; the arguments below go inside `params`. In `?mode=all`, call the action name directly with those arguments. `browse_github` and `read_docs` are direct tools in both modes. Expand each schema for nested fields, enum values and validation constraints. Successful results are JSON in both text content and `structuredContent`; failures use `isError` and `structuredContent.error`.

The [OpenAI profile](/mcp/openai-profile.md) calls individual actions, omits `get_byod_token`, and restricts credential inputs and environment outputs. The input schemas below describe the standard catalog; profile-specific schemas are included where they differ.

## `manage_domain`

Custom domains for an app (its organization's members who can edit it). action=reserve returns the DNS record the user must create at their DNS provider; action=add verifies that record, issues the certificate and attaches the domain (domain\_not\_verified with the record until DNS is in place: retry after the user created it); action=remove detaches it; action=set\_default picks the domain the dashboard shows as the app's address (null for the Kinesis-issued one). get\_app lists attached domains under config.domains.

**Group:** `apps` · **Behavior:** Write

**Compact tool:** `apps_write` · **Action:** `manage_domain`

**MCP annotations:** `readOnlyHint: false` · `destructiveHint: true` · `idempotentHint: false` · `openWorldHint: true`

### Permissions and REST equivalents

| Operation                 | REST                                                         | Required scopes |
| ------------------------- | ------------------------------------------------------------ | --------------- |
| `apps.domains.reserve`    | `POST /projects/{projectId}/apps/{appId}/domains/reserve`    | `apps:write`    |
| `apps.domains.add`        | `POST /projects/{projectId}/apps/{appId}/domains`            | `apps:write`    |
| `apps.domains.remove`     | `DELETE /projects/{projectId}/apps/{appId}/domains/{domain}` | `apps:write`    |
| `apps.domains.setDefault` | `POST /projects/{projectId}/apps/{appId}/domains/default`    | `apps:write`    |

### Arguments

| Argument    | Type                                           | Required | Description                                              |
| ----------- | ---------------------------------------------- | -------- | -------------------------------------------------------- |
| `action`    | `"reserve" / "add" / "remove" / "set_default"` | Yes      | What to do                                               |
| `projectId` | `string`                                       | Yes      | Project id                                               |
| `appId`     | `string`                                       | Yes      | App id                                                   |
| `domain`    | `string or null`                               | Yes      | Fully qualified domain name; null only with set\_default |

<details>

<summary>Complete input schema</summary>

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "action": {
      "type": "string",
      "enum": [
        "reserve",
        "add",
        "remove",
        "set_default"
      ],
      "description": "What to do"
    },
    "projectId": {
      "type": "string",
      "pattern": "^[0-9a-fA-F]{24}$",
      "description": "Project id"
    },
    "appId": {
      "type": "string",
      "pattern": "^[0-9a-fA-F]{24}$",
      "description": "App id"
    },
    "domain": {
      "anyOf": [
        {
          "type": "string",
          "pattern": "^(?=.{4,253}$)(?!-)[a-z0-9-]{1,63}(?<!-)(\\.(?!-)[a-z0-9-]{1,63}(?<!-))+$",
          "description": "Fully qualified domain name, e.g. app.example.com"
        },
        {
          "type": "null"
        }
      ],
      "description": "Fully qualified domain name; null only with set_default"
    }
  },
  "required": [
    "action",
    "projectId",
    "appId",
    "domain"
  ],
  "additionalProperties": false
}
```

</details>

### Result

**`apps.domains.reserve`**

* `domain` (`string`): See the complete response schema below.
* `ready` (`boolean`): Verified with an unexpired certificate; add attaches it without further DNS steps
* `dnsRecord` (`object or null`): The record to create; null once no delegation is needed
* `certificate` (`object or null`): Validity of the issued certificate, when one exists

<details>

<summary>Response schema: apps.domains.reserve</summary>

```json
{
  "type": "object",
  "properties": {
    "domain": {
      "type": "string"
    },
    "ready": {
      "type": "boolean",
      "description": "Verified with an unexpired certificate; add attaches it without further DNS steps"
    },
    "dnsRecord": {
      "anyOf": [
        {
          "type": "object",
          "properties": {
            "type": {
              "type": "string",
              "description": "Record type, e.g. CNAME or NS"
            },
            "name": {
              "type": "string",
              "description": "Record name to create"
            },
            "value": {
              "type": "string",
              "description": "Record value"
            }
          },
          "required": [
            "type",
            "name",
            "value"
          ],
          "additionalProperties": false
        },
        {
          "type": "null"
        }
      ],
      "description": "The record to create; null once no delegation is needed"
    },
    "certificate": {
      "anyOf": [
        {
          "type": "object",
          "properties": {
            "notBefore": {
              "anyOf": [
                {
                  "type": "string",
                  "format": "date-time",
                  "description": "ISO 8601 timestamp (UTC)"
                },
                {
                  "type": "null"
                }
              ]
            },
            "notAfter": {
              "anyOf": [
                {
                  "type": "string",
                  "format": "date-time",
                  "description": "ISO 8601 timestamp (UTC)"
                },
                {
                  "type": "null"
                }
              ]
            }
          },
          "required": [
            "notBefore",
            "notAfter"
          ],
          "additionalProperties": false
        },
        {
          "type": "null"
        }
      ],
      "description": "Validity of the issued certificate, when one exists"
    }
  },
  "required": [
    "domain",
    "ready",
    "dnsRecord",
    "certificate"
  ],
  "additionalProperties": false
}
```

</details>

\*\*\`apps.domains.add\`\*\*

* `domain` (`string`): See the complete response schema below.
* `domains` (`array<string>`): Custom domains attached to the app
* `defaultDomain` (`string or null`): Domain the dashboard shows as the app's address; null for the Kinesis-issued one

<details>

<summary>Response schema: apps.domains.add</summary>

```json
{
  "type": "object",
  "properties": {
    "domain": {
      "type": "string"
    },
    "domains": {
      "type": "array",
      "items": {
        "type": "string"
      },
      "description": "Custom domains attached to the app"
    },
    "defaultDomain": {
      "description": "Domain the dashboard shows as the app's address; null for the Kinesis-issued one",
      "type": [
        "string",
        "null"
      ]
    }
  },
  "required": [
    "domain",
    "domains",
    "defaultDomain"
  ],
  "additionalProperties": false
}
```

</details>

Operation-specific errors: `409 domain_not_verified`, `400 grid_to_serverless`, `400 no_suitable_machines`, `400 serverless_gpu_unavailable`, `429 grid_quota_exceeded`. **`apps.domains.remove`**

* `domain` (`string`): See the complete response schema below.
* `domains` (`array<string>`): Custom domains attached to the app
* `defaultDomain` (`string or null`): Domain the dashboard shows as the app's address; null for the Kinesis-issued one
* `deleted` (`true`): See the complete response schema below.

<details>

<summary>Response schema: apps.domains.remove</summary>

```json
{
  "type": "object",
  "properties": {
    "domain": {
      "type": "string"
    },
    "domains": {
      "type": "array",
      "items": {
        "type": "string"
      },
      "description": "Custom domains attached to the app"
    },
    "defaultDomain": {
      "description": "Domain the dashboard shows as the app's address; null for the Kinesis-issued one",
      "type": [
        "string",
        "null"
      ]
    },
    "deleted": {
      "type": "boolean",
      "const": true
    }
  },
  "required": [
    "domain",
    "domains",
    "defaultDomain",
    "deleted"
  ],
  "additionalProperties": false
}
```

</details>

Operation-specific errors: `400 grid_to_serverless`, `400 no_suitable_machines`, `400 serverless_gpu_unavailable`, `429 grid_quota_exceeded`. **`apps.domains.setDefault`**

* `domains` (`array<string>`): Custom domains attached to the app
* `defaultDomain` (`string or null`): Domain the dashboard shows as the app's address; null for the Kinesis-issued one

<details>

<summary>Response schema: apps.domains.setDefault</summary>

```json
{
  "type": "object",
  "properties": {
    "domains": {
      "type": "array",
      "items": {
        "type": "string"
      },
      "description": "Custom domains attached to the app"
    },
    "defaultDomain": {
      "description": "Domain the dashboard shows as the app's address; null for the Kinesis-issued one",
      "type": [
        "string",
        "null"
      ]
    }
  },
  "required": [
    "domains",
    "defaultDomain"
  ],
  "additionalProperties": false
}
```

</details>


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.kinesis.network/mcp/tools/domains.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
