astrid-runtime/astrid · error

MCP attach registration is missing hook_token

Error message

MCP attach registration is missing hook_token

What it means

validate_registration requires every attach registration to carry a hook_token, a shared secret minted by the gateway that authenticates subsequent requests. A missing (empty/whitespace-only) hook_token is rejected before any uplink selection or workspace validation happens. This prevents unauthenticated attaches from proceeding further into gateway state.

Source

Thrown at crates/astrid-cli/src/commands/mcp/gateway.rs:934

    Ok(request)
}

fn validate_registration(registration: &AttachRegistration) -> Result<()> {
    if registration.version != ATTACH_REGISTRATION_VERSION {
        anyhow::bail!(
            "unsupported MCP attach registration version {}",
            registration.version
        );
    }
    super::lifecycle::resolve_principal(Some(&registration.principal))?;
    if registration.host.trim().is_empty() {
        anyhow::bail!("MCP attach registration has an empty host");
    }
    if registration.host_session_id.trim().is_empty() {
        anyhow::bail!("MCP attach registration has an empty host_session_id");
    }
    if registration.hook_token.trim().is_empty() {
        anyhow::bail!("MCP attach registration is missing hook_token");
    }
    validate_workspace(&registration.workspace_abs)?;
    Ok(())
}

fn authenticate_registration(
    registration: &AttachRegistration,
    state: &GatewayState,
) -> Result<astrid_core::PrincipalId> {
    let principal = super::lifecycle::resolve_principal(Some(&registration.principal))?;
    if principal != state.principal {
        anyhow::bail!(
            "MCP attach registration principal '{}' is not the authenticated gateway principal '{}'",
            principal,
            state.principal
        );
    }
    if registration.hook_token != state.hook_token {

View on GitHub (pinned to affd8760f4)

Solutions

  1. Populate hook_token from the gateway's minted token (startup lease / readiness record) before attaching
  2. Verify the readiness file was read successfully and its hook_token field copied into the registration
  3. Regenerate/restart the gateway if the token was lost and re-read the readiness metadata
  4. Log the registration payload (minus secrets) to confirm which field is empty

Example fix

// before
hook_token: String::new(),
// after
hook_token: ready_record.hook_token.clone(),
Defensive patterns

Strategy: validation

Validate before calling

if reg.hook_token.trim().is_empty() { return Err("hook_token is required: read the gateway readiness record first"); }

Type guard

fn has_hook_token(reg: &AttachRegistration) -> bool { !reg.hook_token.trim().is_empty() }

Prevention

When it happens

Trigger: Sending an AttachRegistration via the MCP attach request path with hook_token empty or absent; creating the registration struct manually without copying the token from the gateway startup lease/ready record.

Common situations: Client never read the gateway readiness metadata containing hook_token; placeholder left empty in a config file; token field dropped during payload serialization; tests constructing AttachRegistration by hand.

Related errors


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