Skip to content

Goose: op=mcp_install refuses any config goose itself serialized #1673

Description

@SynthLuvr

Version

codebase-memory-mcp 0.10.5

Platform

Linux (x64)

Install channel

GitHub release archive / install.sh / install.ps1

Binary variant

standard

What happened, and what did you expect?

The one-line installer against a working goose setup fails deterministically at the Goose step, while every other agent (Claude Code, JSON) configures successfully in the same run:

error: agent_config agent=Goose op=mcp_install path=/home/<user>/.config/goose/config.yaml (target: regular file, 4202 bytes)
error: one or more agent configurations failed; the published/current executable was kept, and PATH/index cleanup was not attempted

Expected: the installer appends its codebase-memory-mcp entry under the existing extensions: mapping. Constructs in sibling entries that the editor never touches should not veto the write.

Root cause (verified against main today)

Goose serializes every stdio extension with envs: {} — e.g. an extension goose itself configured looks like:

extensions:
  linux-mcp-server:
    enabled: true
    type: stdio
    name: linux-mcp-server
    cmd: uvx
    args:
    - --python
    - '3.13'
    - linux-mcp-server
    envs: {}
    env_keys: []
    timeout: 300

cbm_upsert_goose_mcp (src/cli/cli.c:3762) → cbm_upsert_yaml_stdio_mcp(..., "extensions", ...)cbm_yaml_upsert_owned_mapping_entryyaml_analyze_mappingyaml_validate_mapping_body, which calls yaml_range_has_unsupported on every body line of the target section (src/cli/config_yaml_edit.c:1407). That check rejects any unquoted { or }:

/* src/cli/config_yaml_edit.c:1271, yaml_range_has_unsupported */
if (c == '{' || c == '}') {
    return YAML_MATCH;   /* caller treats as YAML_ERROR */
}

So any goose config containing at least one stdio extension that goose itself wrote is uneditable by the installer. Flow sequences are fine (args: [] passes — the canonical CBM entry installs cleanly on an otherwise-empty section), which isolates this to flow mappings.

Consequences worth noting:

Bisect evidence (sandboxed $HOME, so the real config was never at risk)

Config shape Result
Real goose config (4 stdio extensions with envs: {}) FAIL
Same, all stdio extensions removed OK
Minimal single-entry config with envs: {} (repro below) FAIL
Identical minus the one envs: {} line OK
Block-style args: converted to flow style args: ["-c", ...] still FAIL
cwd: null / bundled: null lines removed still FAIL
Canonical CBM entry pre-inserted alongside the stdio entry still FAIL

Workaround (verified end-to-end on 0.10.5)

Delete the envs: {} lines (semantically identical for goose — an absent envs key deserializes to an empty env map), then re-run the installer; it completes, writes the entry, and the server passes a stdio MCP handshake. Caveat: goose will re-serialize envs: {} the next time it rewrites config.yaml (e.g. via goose configure), so this recurs on every future codebase-memory-mcp update until fixed.

Suggested fix direction

The editor only upserts its own entry under extensions: — it does not need to interpret flow mappings inside sibling entries' values. #1639 already established the precedent for this class of fix (interior */& treated as text rather than anchors). Alternatively/additionally, carrying the refusal reason out instead of collapsing to -1 (as #1630 asks, and as cbm_daemon_ipc_validation_detail() already does) would have made this a one-minute diagnosis.

Reproduction

No indexing or real code involved — this is a pure installer/config-editor bug, and the repro uses only dummy content.

  1. Config: a minimal fake goose home containing one stdio extension with the envs: {} line goose itself writes:
CBM="$(command -v codebase-memory-mcp)"          # real binary location
mkdir -p "$HOME/cbm-repro/.config/goose"
cat > "$HOME/cbm-repro/.config/goose/config.yaml" <<'EOF'
GOOSE_TELEMETRY_ENABLED: true
extensions:
  demo:
    enabled: true
    type: stdio
    cmd: /bin/true
    args:
    - --serve
    envs: {}
    env_keys: []
    timeout: 300
GOOSE_THINKING_EFFORT: max
EOF
  1. Command (Goose detection triggers via the ~/.config/goose directory; $HOME override sandboxes everything else):
HOME="$HOME/cbm-repro" "$CBM" install -y --force --dir="$(dirname "$CBM")"
  1. Result: error: agent_config agent=Goose op=mcp_install ... and activation aborts (non-zero exit).

  2. Expected: install completes. Proof that the single envs: {} line is the entire trigger:

sed -i '/^    envs: {}$/d' "$HOME/cbm-repro/.config/goose/config.yaml"
HOME="$HOME/cbm-repro" "$CBM" install -y --force --dir="$(dirname "$CBM")"
# → "Install complete."

Both directions verified today on 0.10.5, Linux x86_64.

Logs

codebase-memory-mcp installer
  os:      linux
  arch:    amd64
Stopping active CBM sessions and operations for install...
error: agent_config agent=Goose op=mcp_install path=/home/<user>/.config/goose/config.yaml (target: regular file, 4202 bytes)
error: one or more agent configurations failed; the published/current executable was kept, and PATH/index cleanup was not attempted
error: activation stopped after one or more agent configuration or cleanup operations failed; the published/current executable was kept, and configuration changes that completed may remain. Please restart your coding-agent sessions after resolving the errors above.
Detected agents: Claude-Code Goose

Diagnostics trajectory (memory / performance / leak issues)


Project scale (if relevant)

No response

Confirmations

  • I searched existing issues and this is not a duplicate.
  • My reproduction uses shareable code (a dummy snippet or a public OSS repository), not proprietary code.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingeditor/integrationEditor compatibility and CLI integrationstability/performanceServer crashes, OOM, hangs, high CPU/memorywindowsWindows-specific issues

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions