Skip to content

MCP Configuration Guide

How agents-fleet discovers, configures, and passes MCP (Model Context Protocol) servers to the coordinator and worker sessions.

Overview

agents-fleet supports MCP servers at three levels:

  1. Fleet config — servers declared in ~/.fleet/config.json (always available)
  2. Auto-discovery — servers found in well-known config files from other tools
  3. Crew allowlisting — crews can restrict which MCP servers their agents access

All configured servers are converted to the Copilot SDK format (Record<string, MCPServerConfig>) via toSdkMcpServers() and passed to the SDK's createSession() call.

Configuring MCP Servers

1. Fleet Config (~/.fleet/config.json)

The primary configuration location. Servers here are always available to the coordinator and (unless restricted by a crew) to workers.

jsonc
{
  "mcpServers": [
    {
      "name": "github",
      "transport": "stdio",
      "command": "gh-mcp",
      "args": ["serve"],
      "env": { "GITHUB_TOKEN": "ghp_..." }
    },
    {
      "name": "remote-api",
      "transport": "sse",
      "url": "https://mcp.example.com/sse"
    },
    {
      "name": "stream-api",
      "transport": "streamable-http",
      "url": "https://mcp.example.com/stream"
    }
  ]
}

Fields:

FieldRequiredDescription
nameYesUnique server name (used as reference in crews)
transportYesstdio, sse, or streamable-http
commandstdio onlyCommand to spawn
argsNoArguments for the command
urlsse/http onlyServer URL
envNoEnvironment variables for stdio servers
descriptionNoHuman-readable description

2. The /mcp Command

Manage servers interactively during a session:

/mcp list                              — show configured servers
/mcp add <name> <transport> <cmd|url>  — add a server
/mcp remove <name>                     — remove a server
/mcp status                            — show active servers

Changes persist to ~/.fleet/config.json. A session restart is required for changes to take effect.

Auto-Discovery

agents-fleet automatically scans config files from popular developer tools on startup. Discovery itself is enabled by default and can be controlled via mcpDiscovery in ~/.fleet/config.json:

jsonc
{
  "mcpDiscovery": {
    "enabled": true,                      // default: true
    "sources": ["mcp.json", "vscode"],    // optional: limit which sources to scan
    "excludeServers": ["noisy-server"]    // optional: skip specific server names
  }
}

Project-level MCP is opt-in (SEC-1)

For security, project-scoped MCP config files are skipped by default — loading an MCP server definition that ships inside an untrusted repo is a code-execution risk. The gated sources are <cwd>/.mcp.json, <cwd>/.cursor/mcp.json, <cwd>/.vscode/mcp.json, and <cwd>/agency.toml.

To opt in, either pass --trust-project-mcp on launch or set AGENTS_FLEET_MCP_TRUST_PROJECT=1. User-level configs (~/.fleet/config.json, ~/.cursor/mcp.json, Claude Desktop, ~/.agency/agency.toml) always load — only the project-tier sources are gated.

Supported Discovery Sources

Source IDLocationTrustFormat
mcp.json<project>/.mcp.jsonproject (opt-in){ "mcpServers": { "<name>": { ... } } }
claude%APPDATA%\Claude\claude_desktop_config.json (Win) / ~/.config/claude/claude_desktop_config.json (Unix)user{ "mcpServers": { ... } }
cursor-project<project>/.cursor/mcp.jsonproject (opt-in){ "mcpServers": { ... } }
cursor-user~/.cursor/mcp.jsonuser{ "mcpServers": { ... } }
vscode<project>/.vscode/mcp.json and <project>/.vscode/settings.jsonproject (opt-in)See below
agency<project>/agency.toml (project, opt-in) or ~/.agency/agency.toml (user)mixedTOML [mcps.builtins.<name>] sections

Format Details

.mcp.json (project root)

The standard cross-tool MCP config, also used by the Copilot CLI and other tools:

json
{
  "mcpServers": {
    "my-server": {
      "command": "my-mcp-server",
      "args": ["--port", "3000"],
      "env": { "API_KEY": "..." }
    },
    "remote-server": {
      "url": "https://mcp.example.com/sse",
      "type": "sse"
    }
  }
}

VS Code (two files scanned)

.vscode/mcp.json (dedicated MCP file, takes priority):

json
{
  "mcpServers": {
    "my-tool": { "command": "my-tool-bin" }
  }
}

.vscode/settings.json (two shapes supported):

jsonc
{
  // Flat format
  "mcp.servers": {
    "my-tool": { "command": "my-tool-bin" }
  }
}
jsonc
{
  // Nested format
  "mcp": {
    "servers": {
      "my-tool": { "command": "my-tool-bin" }
    }
  }
}

If the same server name appears in both .vscode/mcp.json and .vscode/settings.json, the mcp.json version wins.

Claude Desktop

json
{
  "mcpServers": {
    "my-tool": {
      "command": "my-tool-bin",
      "args": ["serve"]
    }
  }
}

Cursor

Both project-level (.cursor/mcp.json) and user-level (~/.cursor/mcp.json) use the same format:

json
{
  "mcpServers": {
    "my-tool": { "command": "my-tool-bin" }
  }
}

Agency TOML

toml
[mcps.builtins.bluebird]
enabled = true

[mcps.builtins.raven]
enabled = false

Enabled builtins are spawned via agency mcp <name>.

Priority and Deduplication

When the same server name is found in multiple sources:

  1. Fleet config wins — servers in ~/.fleet/config.json always take precedence over discovered ones
  2. First source wins — among discovered servers, the first source to register a name keeps it
  3. Source scan order: .mcp.json → Claude Desktop → Cursor (project) → Cursor (user) → VS Code → Agency

Copilot CLI and the SDK

The @github/copilot-sdk natively supports MCP servers via the mcpServers field in SessionConfig. The SDK also offers enableConfigDiscovery: true which auto-discovers .mcp.json and .vscode/mcp.json files.

agents-fleet does NOT use enableConfigDiscovery — it performs its own broader discovery (covering Claude, Cursor, Agency, and more) and passes the results explicitly via sessionConfig.mcpServers. This gives fleet full control over which servers are available and enables crew-level allowlisting.

The vanilla Copilot CLI (copilot / github-copilot) does not have a separate MCP config location beyond .mcp.json at the project root. There is no ~/.copilot/mcp.json file — the ~/.copilot/settings.json file stores model/effort preferences only.

How MCP Servers Flow Through the System

~/.fleet/config.json (mcpServers)

         ├──► loadConfig()                        [src/config.ts]


    allMcpServers = config.mcpServers

         ├──► discoverMcpServers(cwd, existing)   [src/mcp/McpDiscovery.ts]
         │    Scans .mcp.json, Claude, Cursor, VS Code, Agency
         │    Deduplicates; fleet config wins


    allMcpServers (fleet + discovered)

         ├──────────────────────┐
         ▼                      ▼
    CoordinatorEngine        FleetManager
    (coordinator session)    (worker sessions)
         │                      │
         ▼                      ▼
    toSdkMcpServers()       resolveMcpServers()  [src/mcp/McpResolver.ts]
         │                      │
         │                      ├── No crew? → all fleet servers
         │                      ├── Crew mcpServers? → filter to allowed names
         │                      └── Agent mcpServers? → override crew default
         │                      │
         │                      ▼
         │                  toSdkMcpServers()
         │                      │
         ▼                      ▼
    SDK SessionConfig       SDK SessionConfig
    { mcpServers: {…} }     { mcpServers: {…} }

Coordinator

The coordinator always receives all configured MCP servers. They're converted by toSdkMcpServers() and passed in the sessionConfig.mcpServers field when createSession() is called.

Runtime toggling is supported via enableMcp() / disableMcp() on CoordinatorEngine, which delegates to the SDK session's mcp.enable() / mcp.disable() methods. This is used by CrewActivator when switching crews.

Workers

Worker MCP access is resolved by McpResolver.resolveMcpServers():

ScenarioResult
No active crewWorker gets all fleet MCP servers
Active crew, no mcpServers declaredWorker gets no MCP servers
Crew-level mcpServers: ["github", "slack"]Worker gets only github and slack
Agent-level mcpServers: ["github"]Overrides crew default — worker gets only github

MCP permission enforcement happens in FleetManager.startWorkerSession() via the onPermissionRequest handler. When a worker makes an MCP tool call, the tool name (format: serverName__toolName) is checked against the agent's allowed set.

Crew-Level MCP Allowlisting

Crews can declare which MCP servers their agents may use. This is defined in crew YAML frontmatter:

Crew-level default (applies to all agents)

yaml
---
name: my-crew
mcpServers: [github, slack]
agents:
  - role: coder
  - role: reviewer
---

Both coder and reviewer get access to github and slack.

Agent-level override

yaml
---
name: my-crew
mcpServers: [github, slack]
agents:
  - role: coder
    mcpServers: [github, slack, jira]   # gets all three
  - role: reviewer
    mcpServers: [github]                 # restricted to github only
---

Agent-level mcpServers completely replaces (not merges with) the crew default.

Important notes

  • Server names in crews reference servers from the fleet registry (~/.fleet/config.json + discovered)
  • If a crew references a server name that doesn't exist in the registry, it's silently ignored
  • The coordinator always has access to all servers regardless of crew configuration

SDK Format Reference

The Copilot SDK (@github/copilot-sdk) expects MCP servers in this format:

typescript
// SessionConfig.mcpServers
Record<string, MCPServerConfig>

// stdio server
{
  "my-server": {
    type: "local",          // or "stdio"
    command: "my-mcp-bin",
    args: ["serve"],
    tools: ["*"],           // which tools to expose
    env: { KEY: "value" },  // optional
    cwd: "/path",           // optional
  }
}

// HTTP/SSE server
{
  "remote-server": {
    type: "http",           // or "sse"
    url: "https://example.com/mcp",
    tools: ["*"],
    headers: { "Authorization": "Bearer ..." },  // optional
  }
}

The fleet's toSdkMcpServers() function (in src/providers/mcpUtils.ts) handles the conversion from McpServerConfig[] to this format. It always sets tools: ["*"] — fine-grained tool filtering is handled by the crew allowlist at the permission layer instead.

Troubleshooting

Servers not appearing

  1. Check ~/.fleet/config.json — is the server listed under mcpServers?
  2. Run /mcp list to see configured servers
  3. Run /mcp status to see active servers in the current session
  4. Check if mcpDiscovery.enabled is set to false
  5. Check if the server is in mcpDiscovery.excludeServers

Discovered servers not loading

  1. Ensure the config file exists in the expected location (see table above)
  2. Ensure the server entry has either command (stdio) or url (sse/http)
  3. Check if another source already registered the same server name (first wins)
  4. Check the startup log for 🔌 Discovered MCPs: messages

Workers can't access MCP tools

  1. Check if a crew is active — crew MCP allowlisting may be restricting access
  2. If a crew is active but has no mcpServers declared, workers get no MCP access
  3. Add the server name to the crew or agent-level mcpServers list