OxagenDocs
MCP server

File-based configuration

Configure MCP servers using settings.json files — offline-first, version-controllable, and CLI-friendly.

The file-based configuration system lets you define MCP servers, permissions, and tool visibility in JSON files. It works offline, supports version control, and mirrors the layered settings approach used by Claude Code.

File hierarchy

Settings are loaded from three scopes, with later scopes overriding earlier ones:

ScopePathVCSPurpose
User (global)~/.config/oxagen/settings.jsonNoPersonal defaults, global MCP servers
Project (shared).oxagen/settings.jsonYesTeam-wide servers, shared permissions
Local (personal).oxagen/settings.local.jsonNo (gitignored)Developer overrides, secrets

Merge order: user < project < local (local wins).

Settings schema

{
  "$schema": "https://oxagen.sh/schemas/settings.v1.json",

  "mcpServers": {
    "github": {
      "transport": "streamable-http",
      "url": "https://api.githubcopilot.com/mcp/",
      "auth": "oauth",
      "oauthServerUrl": "https://api.githubcopilot.com/mcp/",
      "scopes": ["repo", "read:org"]
    },
    "linear": {
      "transport": "sse",
      "url": "https://mcp.linear.app/sse",
      "auth": "bearer",
      "envToken": "LINEAR_MCP_TOKEN"
    },
    "filesystem": {
      "transport": "stdio",
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-filesystem", "./src"]
    }
  },

  "permissions": {
    "defaultMcpPolicy": "ask",
    "mcpServers": {
      "github": {
        "defaultPolicy": "allow",
        "deny": ["delete_repository"]
      }
    }
  },

  "toolVisibility": {
    "github": {
      "include": ["create_pull_request", "list_issues", "get_file_contents"]
    }
  }
}

Server definition fields

HTTP-based servers (streamable-http, sse, websocket)

FieldTypeRequiredDescription
transport"streamable-http" | "sse" | "websocket"YesTransport protocol
urlstringYesServer endpoint URL
auth"none" | "bearer" | "header" | "oauth"NoAuth strategy (default: "none")
envTokenstringNoEnv var name holding the bearer token
headersobjectNoStatic headers (supports ${VAR} expansion)
oauthServerUrlstringNoOAuth authorization server URL
scopesstring[]NoOAuth scopes to request
envobjectNoAdditional env vars for the transport
disabledbooleanNoPresent but not loaded

stdio servers

FieldTypeRequiredDescription
transport"stdio"YesAlways "stdio"
commandstringYesCommand to spawn
argsstring[]NoArguments (supports ${VAR} expansion)
envobjectNoEnv vars for the spawned process
cwdstringNoWorking directory (default: project root)
disabledbooleanNoPresent but not loaded

Merge semantics

SectionMerge behavior
mcpServersKeyed by name. Later scope replaces entire server entry (no deep-merge within a server).
permissions.defaultMcpPolicyLater scope wins.
permissions.mcpServersKeyed by server name. deny/allow lists append; defaultPolicy overwrites.
toolVisibilityKeyed by server name. Later scope fully replaces that server's visibility.

Environment variable expansion

All string values in the settings support ${VAR} expansion:

{
  "mcpServers": {
    "internal": {
      "transport": "streamable-http",
      "url": "https://mcp.internal.${COMPANY_DOMAIN}/v1",
      "auth": "header",
      "headers": { "X-API-Key": "${INTERNAL_MCP_KEY}" }
    }
  }
}

Missing env vars resolve to an empty string and produce a warning on stderr. The server is skipped if the URL becomes empty.

Disabling a server

Set "disabled": true to keep a server in the config without loading it:

{
  "mcpServers": {
    "expensive-server": {
      "transport": "streamable-http",
      "url": "https://expensive.example.com/mcp",
      "auth": "bearer",
      "envToken": "EXPENSIVE_TOKEN",
      "disabled": true
    }
  }
}

Disabled servers appear in oxagen mcp list but are not connected or probed.

Project root detection

The CLI finds the project root by walking up from the current directory looking for an .oxagen/ directory. If none is found, the current working directory is used.

# These all work from any subdirectory of the project:
cd my-project/src/deep/nested
oxagen mcp list  # finds my-project/.oxagen/settings.json

Initializing a project

mkdir -p .oxagen
echo '{}' > .oxagen/settings.json
echo 'settings.local.json' >> .oxagen/.gitignore

Or use the add command which creates the directory and file automatically:

oxagen mcp add my-server --url https://example.com/mcp
# Creates .oxagen/settings.json if it doesn't exist

On this page