> ## Documentation Index
> Fetch the complete documentation index at: https://astronomer.io/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Astro Private Cloud MCP server runbook and error reference

> Diagnose common Astro Private Cloud MCP server failures, read its error codes, and disable the server during an incident.

Use [Symptom to cause](#symptom-to-cause) and the [error reference](#error-reference) to debug a tool call. Use [Disable the server](#disable-the-server) to handle an incident. The sections don't depend on each other.

> [!NOTE]
>
> **Astro Private Cloud 2.2**
>
> This feature was introduced in Astro Private Cloud 2.2. To access this feature, upgrade your Astro Private Cloud installation to 2.2 or later.

## Symptom to cause

### The gate rejects every request

The MCP server has no authentication code of its own. Every request passes through the platform's NGINX ingress first, which makes an `auth_request` subrequest to the APC API's `/v1/authorization/agent` endpoint before the request reaches the MCP server. A rejection at this gate is a plain HTTP 401 at the ingress layer, not a tool-call error, because the request never reached the server's code.

Check, in order:

1. Is the credential valid? The gate accepts APC API JSON Web Tokens (JWTs), service-account keys, and identity provider (IdP) tokens, and clients typically use a service-account API key as a static bearer token. Confirm the token hasn't expired, been rotated, or been deleted. See [Authentication](https://astronomer.io/docs/astro-private-cloud/v-2-x/apc-mcp-server-security.md#authentication).
2. Is a stale cache result being served? The gate caches each verdict by bearer token: a success for `astronomer.mcpServer.authCache.validSuccess` (five minutes by default) and a denial for `astronomer.mcpServer.authCache.validFailure` (one minute by default). A revoked or expired key can keep passing until its cached success expires. A key you just fixed can take up to a minute to start working again.
3. Is bring-your-own-ingress or an Istio Gateway enabled? Both set `global.authSidecar.enabled`, which together with `astronomer.mcpServer.enabled` fails the whole Helm install or upgrade, rather than coming up with an unauthenticated gate. If the server won't deploy, check [Availability](https://astronomer.io/docs/astro-private-cloud/v-2-x/apc-mcp-server-connect.md#availability) before assuming a token problem.

### Laminar unreachable, Laminar returned an error, or the Deployment isn't operator-based

These three causes aren't equally distinguishable. A Deployment that isn't operator-based reports as `unsupported`, since the Airflow-state tools (`get_dag_stats`, `get_dag_run`, `get_dag_run_diagnosis`) only work on operator-based Deployments. Check the Deployment's mode before assuming anything else is wrong.

An unreachable Laminar and a Laminar error both report as `upstream`, so the kind can't tell them apart. The message text that follows the kind names the specific upstream failure. Read the message, not just the kind, when triaging an `upstream` error from these tools.

### Task logs come back empty

The MCP server doesn't distinguish "this task's logs haven't shipped yet" from "this task's logs are gone." Both return a successful response with empty log content, and there's no special error for the in-flight case.

The only signal is the task instance's state, included in the response when the log attempt you asked for matches the task's current attempt number. A `running` state alongside empty content usually means the logs haven't flushed yet, so wait and ask again. A terminal state (`success` or `failed`) alongside empty content more likely means the logs are actually gone (for example, an evicted worker, or a retention window that has passed). If you asked for an earlier attempt than the task's current one, the response omits state entirely, so the signal isn't available for a stale `tryNumber`.

### A tool is missing from `tools/list`

Three causes are possible. The pod's health tells you which:

* Its tool group isn't enabled. Check `astronomer.mcpServer.enabledGroups` in the chart values against the tool's group. This is a normal, healthy state. The pod runs fine either way.
* It's named in `astronomer.mcpServer.disabledTools`. This outranks everything, including an otherwise-enabled group. Also a normal, healthy state. A misspelled name in this list logs a boot-time warning and disables nothing, so check here if a tool you meant to disable is still visible.
* A genuine registration failure. The pod never becomes ready (`CrashLoopBackOff`), rather than running with one tool missing. If the pod is `Running` and ready, the cause is one of the first two. Otherwise, collect the pod logs and contact Astronomer support.

## Error reference

Every tool error is one line, `<kind>: <message>`. The kind is a stable, machine-readable discriminator. The message is free text to read, not pattern-match.

| Kind | Meaning | Retry? |
| - | - | - |
| `denied` | Either a local refusal (for example, a destructive call made without `confirm: true`) or an upstream permission denial. Both read identically. | No. Retrying the identical call won't change the answer. Supply the missing confirmation or get the right permission first. |
| `not_found` | The named resource (Deployment, Dag run, task instance, and so on) doesn't exist under that identifier. | No. |
| `unsupported` | A capability unavailable for this Deployment and terminal (for example, a Helm-based Deployment calling an operator-only tool). | No. The operation can't work here. Use a different Deployment. |
| `upstream` | A classified upstream failure from the APC API, the Deployment's Airflow REST API, or Laminar: a cordoned Deployment, an unreachable upstream or one returning its own error, a concurrency cap, a timeout. | Depends on the message. Some upstream failures are transient and worth retrying after a delay; others (for example, a cordoned Deployment) need an operator action first. The kind alone doesn't tell you which, so read the message. |
| `internal` | An unexpected server error. The message is always the fixed string `an internal error occurred`. | No. Retrying the same arguments won't help. Report it to Astronomer support. |
| `invalid_argument` | A caller-side argument error the caller can fix: an empty required field, a malformed or disallowed value, or a value that conflicts with existing state (for example, a Deployment name already taken). | Yes, but only after changing the offending value. Resending identical arguments fails the same way. When the value was the user's choice (a name), ask the user rather than inventing one. |
| `partial_commit` | A mutation's write already committed, but some other part of the response failed to resolve afterward. | Never retry this call as if the write never happened. Re-read the target's current state first, then decide what to do next. Retrying blind risks applying the same write twice. |

## Disable the server

Options are listed fastest first. There's no in-product toggle, and only the last option is a `helm upgrade`.

1. Revoke the credential at the gate. Revoke or rotate the service-account key through the APC API. Tools that call the APC API fail on the next call, but the gate can keep letting the key through until its cached success expires (five minutes by default). The pod keeps running, and nothing is redeployed.

2. Scale to zero. Immediate, and doesn't touch Helm:

   ```bash theme={null}
   kubectl scale deployment astronomer-mcp-server -n astronomer --replicas=0
   ```

   This assumes the chart was installed under its default release name. If you set `astronomer.mcpServer.fullnameOverride` or used a non-default release name, find the actual Deployment name first:

   ```bash theme={null}
   kubectl get deployment -n astronomer -l component=mcp-server
   ```

   Scaling to zero doesn't change the Helm value, so the APC UI keeps showing the MCP server as enabled, and any client that tries to connect gets errors, until you run a `helm upgrade`. Use this option to stop traffic during an incident, then follow with option 3.

3. Turn off the chart flag, or pin a previous image. Set `astronomer.mcpServer.enabled: false`, or pin `astronomer.images.mcpServer.tag` back to a known-good version, and apply it with a `helm upgrade`. Slower than the previous two options because it's a full upgrade, but it's the only one that removes the component rather than pausing it.

> [!WARNING]
>
> None of these options undo what the server already did. A mutating tool call that committed through the APC API stays committed, and disabling or rolling back the MCP server doesn't roll back its effects. Recover from an unwanted mutation through the APC API's own mechanisms (for example, `rollback_deployment`).
