Skip to main content
An MCP server is a process that speaks the Model Context Protocol. Coding agents that support MCP read a JSON config that lists the servers to launch and how to reach them. gaal manages those entries declaratively: you describe each server once in gaal.yaml and gaal upserts it into the right JSON file for every agent that should see it. The destination path is resolved automatically from the agent registry — you no longer have to spell it out.

The upsert guarantee

Every agent’s MCP config lives inside a larger config file. Claude Code stores MCP servers in ~/.claude.json; VS Code-family agents use ~/.vscode/settings.json; Codex uses ~/.codex/config.toml. You can’t safely overwrite the whole file. gaal reads the target JSON, modifies the mcpServers object in place, and writes it back. Other top-level keys are preserved exactly. That’s the upsert guarantee: gaal never clobbers a config it didn’t author.

Targeting agents, not paths

Each mcps[] entry says which agents to install the server in, and which scope to use. gaal looks up the destination JSON file in the registry.
["*"] is a wildcard that resolves at sync time to every registered agent that has a non-empty MCP config for the requested scope. Agents that don’t expose an MCP config are skipped silently.

Scope: global vs project

In the current registry every built-in agent stores its MCP entries in a single user-global file. Project-scoped MCP configs are reserved for future agents that adopt them. Set global: true for every entry todayglobal: false is a no-op for now.

Two ways to define a server

Inline

The server spec lives directly in gaal.yaml. Stdio servers use command + args + env.

Remote source

For configs maintained elsewhere, point at a URL that returns an mcpServers document. gaal downloads the JSON and merges the entry whose key matches name into each target.
source and inline are mutually exclusive.

HTTP and SSE servers

The MCP spec defines two remote transports: Streamable HTTP and the older HTTP+SSE. gaal can write native remote entries for agents that support them.
If an agent does not support native remote MCP entries yet, use a stdio bridge such as mcp-remote under command and args.

Behaviour during sync

  • The target JSON is updated in place; the named entry is added or refreshed under mcpServers.
  • Other top-level keys in the target file are preserved.
  • Other entries inside mcpServers that gaal didn’t author are preserved.
  • Removing an mcps[] entry from gaal.yaml does not remove it from the target file unless you pass --prune.
  • If the target’s parent directory is missing, the entry is skipped — gaal never creates an agent’s config directory as a side effect.

Behaviour with --prune

gaal sync --prune removes any mcpServers entries from gaal-managed targets that aren’t in gaal.yaml. It only touches keys gaal could plausibly own; your other settings and other servers stay untouched. See Pruning for the exact algorithm.

Migrating from target:

Earlier versions required a target: path on every entry. The field is deprecated but still honoured for backward compatibility — gaal logs a warning when it sees one. Replace it with agents: + global: so the registry resolves the path. To install in more than one agent, list them all in the same entry instead of duplicating it.

Configure MCP servers

Agent integrations

Pruning

Schema: mcps