Skip to main content
An MCP server is an executable that speaks the Model Context Protocol. Coding agents that support MCP read a JSON config that lists the servers to launch and how to launch them. gaal manages those entries declaratively: you write each server once in gaal.yaml, and gaal upserts it into the right JSON file for every agent that should see it.

The upsert guarantee

The thing that makes MCP management painful by hand is that every agent’s MCP config lives inside a larger config file. claude_desktop_config.json has your editor settings; ~/.vscode/settings.json has your VS Code preferences. 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.

Two ways to define a server

Inline

The server spec lives directly in gaal.yaml:
mcps:
  - name: filesystem
    target: ~/.config/claude/claude_desktop_config.json
    inline:
      command: uvx
      args: [mcp-server-filesystem, ~/projects]
      env:
        FOO: bar
The inline block follows the standard MCP server schema: command, args, env.

Remote source

For configs maintained elsewhere, point at a URL that returns an mcpServers document. gaal downloads the JSON and merges its mcpServers entries into the target.
mcps:
  - name: github
    source: https://raw.githubusercontent.com/github/mcp-servers/main/config.json
    target: ~/.config/claude/claude_desktop_config.json
source and inline are mutually exclusive.

Targets

target: is an absolute or ~/-prefixed path to the JSON file you want to upsert into. Common targets:
AgentTarget
Claude Desktop~/.config/claude/claude_desktop_config.json
VS Code (Copilot, Cline, Roo)~/.vscode/settings.json
Cursor~/.cursor/mcp.json
Codex~/.codex/mcp.json
Windsurf~/.codeium/windsurf/mcp_settings.json
Continue~/.continue/config.json
The target file doesn’t need to exist beforehand, gaal will create it. Each agent integration page lists the canonical target for that agent.

Targeting multiple agents

Each mcps[] entry has exactly one target. To install the same server in two agents, declare it twice:
mcps:
  - name: filesystem
    target: ~/.config/claude/claude_desktop_config.json
    inline:
      command: uvx
      args: [mcp-server-filesystem, ~/projects]

  - name: filesystem
    target: ~/.cursor/mcp.json
    inline:
      command: uvx
      args: [mcp-server-filesystem, ~/projects]
This is intentional. Some servers want different arguments per agent, and the explicit per-target entry makes that obvious in the file.

Behaviour during sync

  • The target JSON is created if missing.
  • The named entry is added or updated under mcpServers.
  • Other keys in the file (and other servers under mcpServers that you added by hand) are preserved.
  • Removing an mcps[] entry from gaal.yaml does not remove it from the target file unless you pass --prune.

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 config and other servers stay untouched. See Pruning for the exact algorithm.

Configure MCP servers

Agent integrations

Pruning

Schema: mcps