# MCP server

> Connect Claude Code, Cursor, or Codex to ZopDay; ask about projects, services, deploys, infrastructure and live Kubernetes state in plain language.

Source: https://zop.dev/docs/zopday/integrations/mcp

---

The ZopDay MCP server lets an AI assistant read your platform directly. Ask Claude "why did the checkout service's last deploy fail?" and it reads the real deploy events, pod logs and Kubernetes warnings instead of guessing.

It speaks the **Model Context Protocol** over Streamable HTTP, so any MCP-capable client works.

## What you can connect

Any client that speaks MCP over Streamable HTTP, including:

- **Claude Code**
- **Claude Desktop**
- **Cursor**
- **Antigravity**
- **Codex**, **Devin** and **Grok build**

## The connection URL

One URL serves every client. Copy yours from either place in the app:

- **Settings → Organisation**, in the **MCP Server** section
- **Developer Settings**, on the screen where you create your token

Copying it from the app rather than typing it means you always get the right host for your environment. The blocks below call it `MCP_SERVER_URL`, and your token `MCP_PAT`.

## Create a token

The server authenticates with a personal access token, prefixed `zn_pat_`.

**Enable MCP for the organisation**

  Open **Settings → Organisation**, scroll to the **MCP Server** section, and switch the toggle on. The badge changes from Inactive to Active and the server URL appears. Only a user with the Organisation Update permission sees the toggle.

**Open Developer Settings**

  Click your profile avatar at the bottom-left of the sidebar, then **Developer Settings**.

**Create the token**

  Under **Personal Access Tokens**, click **Create Token**, give it a name such as "Cursor" or "Claude Code", choose an expiry, and confirm.

**Copy it once**

  The token is shown only once. Copy it straight into your secret manager, never into a committed file.

A token carries your identity, not a narrower one. Every call resolves your live role at the moment it is made, so mint it as the person with the narrowest role that does the job. See [Authentication](https://zop.dev/docs/zopday/authentication).

## Configure your client

Every client needs the same two values, and nothing else:

- the **URL** from the step above
- your **token**, sent as an `Authorization: Bearer …` header

If your client has a form for these (Cursor does), just paste the two values in and it writes its own config. The blocks below are for clients where you edit the config file yourself, or where the only way in is the command line.

### Claude Code

```bash
claude mcp add zopday MCP_SERVER_URL -t http -H "Authorization: Bearer MCP_PAT"
```

The `-t http` flag is required. Transport defaults to `stdio`, so without it your URL is recorded as a program to execute. The command does warn — *"looks like a URL, but is being interpreted as a stdio server"* — but it still succeeds and still adds the broken entry, so the symptom you actually notice is a connection that never works. Substitute both placeholders before running it, since nothing validates them either.

This adds the server for you in the current directory only. Add `-s user` to use it from every project. Then check it actually connected:

```bash
claude mcp list
```

The name `zopday` is just the local label for the connection; pick whatever you like.

### Claude Desktop

Claude Desktop has no config block for this. Every documented walkthrough of `claude_desktop_config.json` covers local servers that Desktop launches by `command`; the supported route for a remote server is a custom connector. Add it through the interface:

**Open the connector form**

  On Free, Pro and Max: **Customize → Connectors → Add custom connector**. On Team and Enterprise an Owner has to add it first, from **Organization settings → Connectors → Add → Custom**; members then find it under **Customize → Connectors** and click **Connect**.

**Enter the URL**

  Paste your server URL.

**Add the token as a header**

  Under **Request headers**, add `Authorization` with the value `Bearer ` followed by your token. The value is sent exactly as typed, so the word `Bearer` and the space after it must be there. Leave the header marked **Required**: a required header with no stored value fails the connection, while an optional one is silently omitted.

Request header authentication is in beta and rolling out gradually, so if there is no **Request headers** section in your dialog you need to ask Anthropic for access. Header names come from a fixed allowlist (`authorization`, `x-api-key`, `x-auth-token` and similar), and you can add up to four.

### Cursor

Open **Customize → MCPs → New MCP Server**, then paste this and save:

```json
{
  "mcpServers": {
    "zopday": {
      "url": "MCP_SERVER_URL",
      "headers": {
        "Authorization": "Bearer MCP_PAT"
      }
    }
  }
}
```

### Antigravity

Open **Settings → Customization → MCP Config**, then paste this and save:

```json
{
  "mcpServers": {
    "zopday": {
      "serverUrl": "MCP_SERVER_URL",
      "headers": {
        "Authorization": "Bearer MCP_PAT"
      }
    }
  }
}
```

The field **must** be `serverUrl`; Antigravity does not support `url` or `httpUrl`. After saving, press the refresh button in the **Installed MCP Servers** panel, or toggle the server off and on, for the change to take effect.

### Codex

Codex has a form for this, so there is no config file to edit:

**Open the MCP settings**

  Open **Settings → Plugins → MCPs**.

**Add a server**

  Click **Add**, then set **Type** to **Streamable HTTP**.

**Enter the details**

  Set **Name** to `zopday`, and **URL** to `MCP_SERVER_URL`.

**Add the token as a header**

  Under **Headers**, add a row with Key `Authorization` and Value `Bearer MCP_PAT`. Use the **Headers** section, not the **Bearer token env var** field.

**Save**

  Click **Save**.

### Devin

Devin has a form for this, so there is no config file to edit:

**Open the MCP settings**

  Open **Devin Settings → Configuration → MCP Servers**.

**Add a custom server**

  Click **Add Custom**.

**Paste the config and save**

  Paste the config below and save:

  ```json
  {
    "mcpServers": {
      "zopday": {
        "url": "MCP_SERVER_URL",
        "headers": {
          "Authorization": "Bearer MCP_PAT"
        }
      }
    }
  }
  ```

### Grok build

Grok CLI adds the server in one command:

```bash
grok mcp add --transport http zopday MCP_SERVER_URL --header "Authorization: Bearer MCP_PAT"
```

## Confirm it works

Start a fresh session and ask:

```text
List my organisations
```

A working connection calls `list_organisations` and reads back your organisations by name. Run this first: it isolates the connection from everything else, because `list_organisations` is the only tool that needs no arguments, and every other tool takes the `org_id` it returns.

If it fails, the usual causes are the transport flag, an expired token, or the organisation toggle still being off.

## What the tools cover

The ZopDay side of the catalogue is **44 tools**, grouped by area below with a few examples of each:

| Area | Covers | For example |
|---|---|---|
| **Organisations & permissions** | The organisations you can reach, their settings, and what your own token may do | `list_organisations`, `get_my_permissions` |
| **Projects & environments** | Projects, rollup stats, a project's environments and where each runs, and creating either | `list_projects`, `list_environments`, `create_project`, `create_environment` |
| **Services & deploys** | Services in an environment, runtime config, deploy history, public URLs, and the deploy, redeploy, rollback, config and env var set | `get_service_overview`, `list_deploys`, `deploy_service`, `rollback_service`, `set_service_env_vars` |
| **Git integrations** | Connected integrations, deployable repositories, branches, and a GitHub App install link | `list_integrations`, `list_repositories`, `list_branches`, `connect_github` |
| **Infrastructure & provisioning** | Clusters, VM pools and datastores as one board, and provisioning jobs with step-level progress and failure detail | `list_infrastructure`, `list_provisioning_jobs`, `get_provisioning_job_overview`, `create_provisioning_job` |
| **Kubernetes & diagnostics** | One-call diagnosis of an unhealthy service, deploy event history, live objects and manifests, cluster warnings, pod logs and live metrics | `diagnose_service`, `get_pod_logs`, `list_k8s_events`, `get_k8s_resource`, `restart_k8s_workload` |

For the authoritative list, call `tools/list` or ask your assistant what tools it has. It is filtered to what your token and role allow, so it is the answer for *you* rather than the whole catalogue. It is not narrowed by product, though: one server carries the whole Zop catalogue, so expect the reply to be longer than the table above. Group your questions around the areas here and the assistant picks from them.

Two tools are worth leading with. **`diagnose_service`** answers "why is this broken" in one call, fusing the service's status, its deploy events and the live cluster state. **`get_service_overview`** answers everything about one service: current revision, recent deploys, last events and public URL.

## What is never returned

Two boundaries hold for every tool, at every level of write access, for every role.

- **No environment variable value.** `get_service_config` returns variable *names* with every value replaced by `***`, and `list_deploys` never returns the values a deploy snapshotted. There is no tool that reveals one; if you need a value, read it in the ZopDay UI.
- **No credentials.** No tool returns a cluster kubeconfig, CA certificate, service-account token, datastore password or vault key. Responses are built from an allowlist rather than by stripping fields from a passthrough, so a new field cannot leak by being forgotten. `get_k8s_manifest` refuses Kubernetes Secrets outright, and `get_k8s_resource` reports a Secret's key names and sizes only.

## Reads and writes

Most tools **read**. A smaller set **writes**: it ships a deploy, changes a service's configuration, provisions infrastructure, or deletes something.

How much an agent may change is one setting per organisation, **Write access**, in **Settings → Organisation**. The levels are cumulative, so choosing one admits everything below it. ZopDay has no metadata-only writes, so its tools begin at the third level:

| Write access | Admits | For example |
|---|---|---|
| **Read-only** | Nothing. Read tools only. | — |
| **Metadata only** | Records only, no cloud state and no cost. | No ZopDay tools sit at this level |
| **Reversible changes** | Bounded blast radius, may affect cost. | Deploys, rollbacks, service config, env vars, auto-deploy, creating projects and environments |
| **Irreversible changes** | No undo, or incurs cost. | Provisioning and teardown, deleting services and projects, Kubernetes writes |

An agent can never exceed the permissions of the person whose token it holds. Your role is resolved on every call, so revoking someone's access in the app takes effect on their next tool call, and every write is recorded in the [audit trail](https://zop.dev/docs/zopday/operations/audit-logs).

**Warning**

Enabling MCP write means any content in your cloud environment becomes a potential instruction to your agent. Service names, commit messages, tags and log lines are strings other people can influence, and a read tool hands them to a model that can call write tools. The control that matters is how much authority the agent has, which is what this setting is.

## Where to next

- **[Quickstart](https://zop.dev/docs/zopday/quickstart)**: connect a cloud account, register a cluster, and ship a first deploy.
- **[Pipelines](https://zop.dev/docs/zopday/pipelines)**: how a deploy actually runs, from trigger to live URL.
