> 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/server-setup.md).

# Server setup and SSH

Attach a machine, configure Smart Lifecycle and manage SSH public keys.

Attach a machine, configure Smart Lifecycle and manage SSH public keys.

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 public BYOD action registers through Kinesis Remote Reach; its response retains the wire field `needVpn`. It accepts token expiry and renewal options, not connection-mode or SSH-management options. Portal onboarding offers a separate network guide. Install SSH keys only on the `eligibleServers` returned by `list_ssh_keys`; Remote Reach machines and rented marketplace machines are ineligible.

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.

## `get_byod_token`

Get a provision token and install command for attaching a machine. The one-line command attaches it (bring your own device) as one of the organization's servers. The same usable token comes back on repeated calls until it is consumed or expires; forceNew mints a fresh one.

**Group:** `servers` · **Behavior:** Write

**Compact tool:** `servers_write` · **Action:** `get_byod_token`

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

### Permissions and REST equivalents

| Operation           | REST                       | Required scopes |
| ------------------- | -------------------------- | --------------- |
| `servers.byodToken` | `POST /servers/byod-token` | `pools:write`   |

### Arguments

| Argument       | Type      | Required | Description                                                                                      |
| -------------- | --------- | -------- | ------------------------------------------------------------------------------------------------ |
| `expiresInSec` | `integer` | No       | Lifetime of a newly minted token, 3600 by default                                                |
| `forceNew`     | `boolean` | No       | Mint a new token even when a usable one exists                                                   |
| `org`          | `string`  | No       | Slug of the organization to act in (see orgs.list); needed when the caller reaches more than one |

<details>

<summary>Complete input schema</summary>

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "expiresInSec": {
      "type": "integer",
      "minimum": 60,
      "maximum": 604800,
      "description": "Lifetime of a newly minted token, 3600 by default"
    },
    "forceNew": {
      "type": "boolean",
      "description": "Mint a new token even when a usable one exists"
    },
    "org": {
      "description": "Slug of the organization to act in (see orgs.list); needed when the caller reaches more than one",
      "type": "string",
      "minLength": 3,
      "maxLength": 39
    }
  },
  "additionalProperties": false
}
```

</details>

Not available with `profile=openai`; use the portal for this operation.

### Result

* `token` (`string`): Provision token; single use
* `expiresAt` (`string or null`): See the complete response schema below.
* `needVpn` (`boolean`): The machine joins through Kinesis Remote Reach (VPN-backed)
* `expiresInSec` (`integer`): See the complete response schema below.
* `installCommand` (`string`): Run this on the machine as root; it installs the agent and registers it

<details>

<summary>Response schema: servers.byodToken</summary>

```json
{
  "type": "object",
  "properties": {
    "token": {
      "type": "string",
      "description": "Provision token; single use"
    },
    "expiresAt": {
      "anyOf": [
        {
          "type": "string",
          "format": "date-time",
          "description": "ISO 8601 timestamp (UTC)"
        },
        {
          "type": "null"
        }
      ]
    },
    "needVpn": {
      "type": "boolean",
      "description": "The machine joins through Kinesis Remote Reach (VPN-backed)"
    },
    "expiresInSec": {
      "type": "integer"
    },
    "installCommand": {
      "type": "string",
      "description": "Run this on the machine as root; it installs the agent and registers it"
    }
  },
  "required": [
    "token",
    "expiresAt",
    "needVpn",
    "expiresInSec",
    "installCommand"
  ],
  "additionalProperties": false
}
```

</details>

Operation-specific errors: `400 org_required`, `403 key_project_restricted`.

## `list_smart_lifecycle`

The Smart Lifecycle setting of each server the organization owns. On, the platform hibernates it when nothing runs on it (storage billing only) and wakes it when an app needs it

**Group:** `servers` · **Behavior:** Read

**Compact tool:** `servers` · **Action:** `list_smart_lifecycle`

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

### Permissions and REST equivalents

| Operation                     | REST                           | Required scopes |
| ----------------------------- | ------------------------------ | --------------- |
| `servers.smartLifecycle.list` | `GET /servers/smart-lifecycle` | `pools:read`    |

### Arguments

| Argument | Type     | Required | Description                                                                                      |
| -------- | -------- | -------- | ------------------------------------------------------------------------------------------------ |
| `org`    | `string` | No       | Slug of the organization to act in (see orgs.list); needed when the caller reaches more than one |

<details>

<summary>Complete input schema</summary>

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "org": {
      "description": "Slug of the organization to act in (see orgs.list); needed when the caller reaches more than one",
      "type": "string",
      "minLength": 3,
      "maxLength": 39
    }
  },
  "additionalProperties": false
}
```

</details>

### Result

* `servers` (`array<object>`): One entry per server the organization owns

<details>

<summary>Response schema: servers.smartLifecycle.list</summary>

```json
{
  "type": "object",
  "properties": {
    "servers": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "address": {
            "type": "string"
          },
          "enabled": {
            "type": "boolean",
            "description": "The platform hibernates the server when idle and wakes it when an app needs it"
          }
        },
        "required": [
          "address",
          "enabled"
        ],
        "additionalProperties": false
      },
      "description": "One entry per server the organization owns"
    }
  },
  "required": [
    "servers"
  ],
  "additionalProperties": false
}
```

</details>

Operation-specific errors: `400 org_required`, `403 key_project_restricted`.

## `set_smart_lifecycle`

Turn automatic hibernate and wake-up (Smart Lifecycle) on or off. For the org's servers

**Group:** `servers` · **Behavior:** Write

**Compact tool:** `servers_write` · **Action:** `set_smart_lifecycle`

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

### Permissions and REST equivalents

| Operation                       | REST                             | Required scopes |
| ------------------------------- | -------------------------------- | --------------- |
| `servers.smartLifecycle.update` | `PATCH /servers/smart-lifecycle` | `pools:write`   |

### Arguments

| Argument    | Type            | Required | Description                                                                                      |
| ----------- | --------------- | -------- | ------------------------------------------------------------------------------------------------ |
| `addresses` | `array<string>` | Yes      | Server addresses, at most 50                                                                     |
| `enabled`   | `boolean`       | Yes      | On or off                                                                                        |
| `org`       | `string`        | No       | Slug of the organization to act in (see orgs.list); needed when the caller reaches more than one |

<details>

<summary>Complete input schema</summary>

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "addresses": {
      "minItems": 1,
      "maxItems": 50,
      "type": "array",
      "items": {
        "type": "string",
        "pattern": "^0x[0-9a-fA-F]{40}$"
      },
      "description": "Server addresses, at most 50"
    },
    "enabled": {
      "type": "boolean",
      "description": "On or off"
    },
    "org": {
      "description": "Slug of the organization to act in (see orgs.list); needed when the caller reaches more than one",
      "type": "string",
      "minLength": 3,
      "maxLength": 39
    }
  },
  "required": [
    "addresses",
    "enabled"
  ],
  "additionalProperties": false
}
```

</details>

### Result

* `servers` (`array<object>`): One entry per server the organization owns

<details>

<summary>Response schema: servers.smartLifecycle.update</summary>

```json
{
  "type": "object",
  "properties": {
    "servers": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "address": {
            "type": "string"
          },
          "enabled": {
            "type": "boolean",
            "description": "The platform hibernates the server when idle and wakes it when an app needs it"
          }
        },
        "required": [
          "address",
          "enabled"
        ],
        "additionalProperties": false
      },
      "description": "One entry per server the organization owns"
    }
  },
  "required": [
    "servers"
  ],
  "additionalProperties": false
}
```

</details>

Operation-specific errors: `400 org_required`, `403 key_project_restricted`.

## `list_ssh_keys`

The organization's SSH public keys and where each is installed (admins). Also its servers a key can be installed on (those added without Kinesis Remote Reach)

**Group:** `servers` · **Behavior:** Read

**Compact tool:** `servers` · **Action:** `list_ssh_keys`

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

### Permissions and REST equivalents

| Operation      | REST            | Required scopes |
| -------------- | --------------- | --------------- |
| `sshKeys.list` | `GET /ssh-keys` | `pools:read`    |

### Arguments

| Argument | Type     | Required | Description                                                                                      |
| -------- | -------- | -------- | ------------------------------------------------------------------------------------------------ |
| `org`    | `string` | No       | Slug of the organization to act in (see orgs.list); needed when the caller reaches more than one |

<details>

<summary>Complete input schema</summary>

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "org": {
      "description": "Slug of the organization to act in (see orgs.list); needed when the caller reaches more than one",
      "type": "string",
      "minLength": 3,
      "maxLength": 39
    }
  },
  "additionalProperties": false
}
```

</details>

### Result

* `keys` (`array<object>`): See the complete response schema below.
* `eligibleServers` (`array<object>`): Servers a key can be assigned to

<details>

<summary>Response schema: sshKeys.list</summary>

```json
{
  "type": "object",
  "properties": {
    "keys": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Key id"
          },
          "label": {
            "type": "string"
          },
          "fingerprint": {
            "type": "string"
          },
          "servers": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Addresses of the servers the key is installed on"
          },
          "createdAt": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time",
                "description": "ISO 8601 timestamp (UTC)"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "id",
          "label",
          "fingerprint",
          "servers",
          "createdAt"
        ],
        "additionalProperties": false
      }
    },
    "eligibleServers": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "address": {
            "type": "string"
          },
          "csp": {
            "type": [
              "string",
              "null"
            ]
          },
          "region": {
            "type": [
              "string",
              "null"
            ]
          },
          "instanceType": {
            "type": [
              "string",
              "null"
            ]
          },
          "ipAddress": {
            "description": "What ssh connects to",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "address",
          "csp",
          "region",
          "instanceType",
          "ipAddress"
        ],
        "additionalProperties": false
      },
      "description": "Servers a key can be assigned to"
    }
  },
  "required": [
    "keys",
    "eligibleServers"
  ],
  "additionalProperties": false
}
```

</details>

Operation-specific errors: `400 org_required`, `403 key_project_restricted`.

## `add_ssh_key`

Register an SSH public key under a label. OpenSSH format; assign it to servers afterwards

**Group:** `servers` · **Behavior:** Write

**Compact tool:** `servers_write` · **Action:** `add_ssh_key`

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

### Permissions and REST equivalents

| Operation        | REST             | Required scopes |
| ---------------- | ---------------- | --------------- |
| `sshKeys.create` | `POST /ssh-keys` | `pools:write`   |

### Arguments

| Argument    | Type     | Required | Description                                                                                      |
| ----------- | -------- | -------- | ------------------------------------------------------------------------------------------------ |
| `label`     | `string` | Yes      | A name for the key                                                                               |
| `publicKey` | `string` | Yes      | The public key, e.g. the contents of id\_ed25519.pub                                             |
| `org`       | `string` | No       | Slug of the organization to act in (see orgs.list); needed when the caller reaches more than one |

<details>

<summary>Complete input schema</summary>

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "label": {
      "type": "string",
      "minLength": 1,
      "maxLength": 64,
      "description": "A name for the key"
    },
    "publicKey": {
      "type": "string",
      "minLength": 1,
      "maxLength": 16384,
      "description": "The public key, e.g. the contents of id_ed25519.pub"
    },
    "org": {
      "description": "Slug of the organization to act in (see orgs.list); needed when the caller reaches more than one",
      "type": "string",
      "minLength": 3,
      "maxLength": 39
    }
  },
  "required": [
    "label",
    "publicKey"
  ],
  "additionalProperties": false
}
```

</details>

### Result

* `id` (`string`): Key id
* `label` (`string`): See the complete response schema below.
* `fingerprint` (`string`): See the complete response schema below.
* `servers` (`array<string>`): Addresses of the servers the key is installed on
* `createdAt` (`string or null`): See the complete response schema below.

<details>

<summary>Response schema: sshKeys.create</summary>

```json
{
  "type": "object",
  "properties": {
    "id": {
      "type": "string",
      "description": "Key id"
    },
    "label": {
      "type": "string"
    },
    "fingerprint": {
      "type": "string"
    },
    "servers": {
      "type": "array",
      "items": {
        "type": "string"
      },
      "description": "Addresses of the servers the key is installed on"
    },
    "createdAt": {
      "anyOf": [
        {
          "type": "string",
          "format": "date-time",
          "description": "ISO 8601 timestamp (UTC)"
        },
        {
          "type": "null"
        }
      ]
    }
  },
  "required": [
    "id",
    "label",
    "fingerprint",
    "servers",
    "createdAt"
  ],
  "additionalProperties": false
}
```

</details>

Operation-specific errors: `400 org_required`, `403 key_project_restricted`.

## `remove_ssh_key`

Delete an SSH key; it is removed from every server it was installed on

**Group:** `servers` · **Behavior:** Write

**Compact tool:** `servers_write` · **Action:** `remove_ssh_key`

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

### Permissions and REST equivalents

| Operation        | REST                       | Required scopes |
| ---------------- | -------------------------- | --------------- |
| `sshKeys.delete` | `DELETE /ssh-keys/{keyId}` | `pools:write`   |

### Arguments

| Argument | Type     | Required | Description                                                                                      |
| -------- | -------- | -------- | ------------------------------------------------------------------------------------------------ |
| `keyId`  | `string` | Yes      | Key id from the list                                                                             |
| `org`    | `string` | No       | Slug of the organization to act in (see orgs.list); needed when the caller reaches more than one |

<details>

<summary>Complete input schema</summary>

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "keyId": {
      "type": "string",
      "minLength": 1,
      "description": "Key id from the list"
    },
    "org": {
      "description": "Slug of the organization to act in (see orgs.list); needed when the caller reaches more than one",
      "type": "string",
      "minLength": 3,
      "maxLength": 39
    }
  },
  "required": [
    "keyId"
  ],
  "additionalProperties": false
}
```

</details>

### Result

* `deleted` (`true`): See the complete response schema below.

<details>

<summary>Response schema: sshKeys.delete</summary>

```json
{
  "type": "object",
  "properties": {
    "deleted": {
      "type": "boolean",
      "const": true
    }
  },
  "required": [
    "deleted"
  ],
  "additionalProperties": false
}
```

</details>

Operation-specific errors: `400 org_required`, `403 key_project_restricted`.

## `assign_ssh_key`

Install an organization SSH key on eligible servers, or remove it (admins). action=assign installs it (on the servers list\_ssh\_keys names under eligibleServers); action=unassign removes it from them. ssh @ then works with the matching private key.

**Group:** `servers` · **Behavior:** Write

**Compact tool:** `servers_write` · **Action:** `assign_ssh_key`

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

### Permissions and REST equivalents

| Operation          | REST                               | Required scopes |
| ------------------ | ---------------------------------- | --------------- |
| `sshKeys.assign`   | `POST /ssh-keys/{keyId}/servers`   | `pools:write`   |
| `sshKeys.unassign` | `DELETE /ssh-keys/{keyId}/servers` | `pools:write`   |

### Arguments

| Argument    | Type                    | Required | Description                                                                                      |
| ----------- | ----------------------- | -------- | ------------------------------------------------------------------------------------------------ |
| `action`    | `"assign" / "unassign"` | Yes      | Install or remove                                                                                |
| `keyId`     | `string`                | Yes      | Key id from the list                                                                             |
| `addresses` | `array<string>`         | Yes      | Server addresses, at most 50                                                                     |
| `org`       | `string`                | No       | Slug of the organization to act in (see orgs.list); needed when the caller reaches more than one |

<details>

<summary>Complete input schema</summary>

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "action": {
      "type": "string",
      "enum": [
        "assign",
        "unassign"
      ],
      "description": "Install or remove"
    },
    "keyId": {
      "type": "string",
      "minLength": 1,
      "description": "Key id from the list"
    },
    "addresses": {
      "minItems": 1,
      "maxItems": 50,
      "type": "array",
      "items": {
        "type": "string",
        "pattern": "^0x[0-9a-fA-F]{40}$"
      },
      "description": "Server addresses, at most 50"
    },
    "org": {
      "description": "Slug of the organization to act in (see orgs.list); needed when the caller reaches more than one",
      "type": "string",
      "minLength": 3,
      "maxLength": 39
    }
  },
  "required": [
    "action",
    "keyId",
    "addresses"
  ],
  "additionalProperties": false
}
```

</details>

### Result

**`sshKeys.assign`**

* `id` (`string`): Key id
* `label` (`string`): See the complete response schema below.
* `fingerprint` (`string`): See the complete response schema below.
* `servers` (`array<string>`): Addresses of the servers the key is installed on
* `createdAt` (`string or null`): See the complete response schema below.

<details>

<summary>Response schema: sshKeys.assign</summary>

```json
{
  "type": "object",
  "properties": {
    "id": {
      "type": "string",
      "description": "Key id"
    },
    "label": {
      "type": "string"
    },
    "fingerprint": {
      "type": "string"
    },
    "servers": {
      "type": "array",
      "items": {
        "type": "string"
      },
      "description": "Addresses of the servers the key is installed on"
    },
    "createdAt": {
      "anyOf": [
        {
          "type": "string",
          "format": "date-time",
          "description": "ISO 8601 timestamp (UTC)"
        },
        {
          "type": "null"
        }
      ]
    }
  },
  "required": [
    "id",
    "label",
    "fingerprint",
    "servers",
    "createdAt"
  ],
  "additionalProperties": false
}
```

</details>

Operation-specific errors: `400 org_required`, `403 key_project_restricted`. **`sshKeys.unassign`**

* `id` (`string`): Key id
* `label` (`string`): See the complete response schema below.
* `fingerprint` (`string`): See the complete response schema below.
* `servers` (`array<string>`): Addresses of the servers the key is installed on
* `createdAt` (`string or null`): See the complete response schema below.

<details>

<summary>Response schema: sshKeys.unassign</summary>

```json
{
  "type": "object",
  "properties": {
    "id": {
      "type": "string",
      "description": "Key id"
    },
    "label": {
      "type": "string"
    },
    "fingerprint": {
      "type": "string"
    },
    "servers": {
      "type": "array",
      "items": {
        "type": "string"
      },
      "description": "Addresses of the servers the key is installed on"
    },
    "createdAt": {
      "anyOf": [
        {
          "type": "string",
          "format": "date-time",
          "description": "ISO 8601 timestamp (UTC)"
        },
        {
          "type": "null"
        }
      ]
    }
  },
  "required": [
    "id",
    "label",
    "fingerprint",
    "servers",
    "createdAt"
  ],
  "additionalProperties": false
}
```

</details>

Operation-specific errors: `400 org_required`, `403 key_project_restricted`.


---

# 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/server-setup.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.
