astrid-runtime/astrid · error

MCP gateway is ready for principal '{}', not '{}'; run `aos

Error message

MCP gateway is ready for principal '{}', not '{}'; run `aos mcp ready --format hook` for the active principal

What it means

The MCP attach command reads the gateway's ready-file and verifies it was written for the caller's principal. If the ready-file names a different principal than the active caller, attach is refused with this error, because the gateway handshake would authenticate the wrong identity.

Source

Thrown at crates/astrid-cli/src/commands/mcp/attach.rs:36

};

/// Attach this process's stdio to the principal's persistent MCP gateway.
///
/// `workspace` is host project context, not an Astrid home or daemon root. It
/// is sent in a small registration preface so the gateway can preserve the
/// caller's `cwd://` root while sharing one daemon uplink across windows.
pub(crate) async fn run(_principal: Option<&str>, workspace: Option<&Path>) -> Result<ExitCode> {
    // The process-wide principal was authenticated before dispatch. Never
    // treat a registration field as the source of authority for this attach.
    let caller = crate::principal::current();
    let socket = gateway_socket_path()?;
    let ready = read_gateway_ready()?.ok_or_else(|| {
        anyhow::anyhow!(
            "MCP gateway is not ready for principal '{caller}'; run `aos mcp ready --format hook`"
        )
    })?;
    if ready.principal != caller.to_string() {
        anyhow::bail!(
            "MCP gateway is ready for principal '{}', not '{}'; run `aos mcp ready --format hook` for the active principal",
            ready.principal,
            caller
        );
    }
    let stream = UnixStream::connect(&socket).await.with_context(|| {
        format!(
            "failed to connect to MCP gateway at {}; run `aos mcp ready --format hook`",
            socket.display()
        )
    })?;

    let registration = build_registration(&caller, workspace, &ready)?;
    let mut stream = stream;
    let header =
        serde_json::to_vec(&registration).context("failed to encode MCP attach registration")?;
    stream
        .write_all(&header)

View on GitHub (pinned to affd8760f4)

Solutions

  1. Re-run `aos mcp ready --format hook` as the currently active principal to refresh the ready-file
  2. Switch back to the principal the gateway is ready for before attaching
  3. Delete the stale ready-file and redo the ready + attach sequence

Example fix

// before
$ aos agent use alice && aos mcp attach   # ready-file still for bob
// after
$ aos mcp ready --format hook             # as alice
$ aos mcp attach
Defensive patterns

Strategy: validation

Validate before calling

let ready = read_gateway_ready()?;
if ready.as_ref().map(|r| r.principal.clone()).as_deref() != Some(&caller.to_string()) {
    // re-run `aos mcp ready --format hook` as the active principal first
}

Type guard

fn ready_matches(ready: &GatewayReady, caller: &PrincipalId) -> bool { ready.principal == caller.to_string() }

Try / catch

match run_attach().await {
    Err(e) if e.to_string().contains("is ready for principal") => {
        run_ready("--format hook")?; // refresh, then retry once
        run_attach().await
    }
    other => other,
}

Prevention

When it happens

Trigger: Running `aos mcp attach` after switching active principals/agents while a ready-file from a previous `aos mcp ready` (for the old principal) still exists.

Common situations: Switching between agents on one machine; running attach from a different shell with a different active principal than the one that ran `mcp ready`; stale ready-file after re-login.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09). Data as JSON: /api/errors/49c836f1d4f9b35f. Report an issue: GitHub.