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:
- Fleet config — servers declared in
~/.fleet/config.json(always available) - Auto-discovery — servers found in well-known config files from other tools
- 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.
{
"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:
| Field | Required | Description |
|---|---|---|
name | Yes | Unique server name (used as reference in crews) |
transport | Yes | stdio, sse, or streamable-http |
command | stdio only | Command to spawn |
args | No | Arguments for the command |
url | sse/http only | Server URL |
env | No | Environment variables for stdio servers |
description | No | Human-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 serversChanges 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:
{
"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 ID | Location | Trust | Format |
|---|---|---|---|
mcp.json | <project>/.mcp.json | project (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.json | project (opt-in) | { "mcpServers": { ... } } |
cursor-user | ~/.cursor/mcp.json | user | { "mcpServers": { ... } } |
vscode | <project>/.vscode/mcp.json and <project>/.vscode/settings.json | project (opt-in) | See below |
agency | <project>/agency.toml (project, opt-in) or ~/.agency/agency.toml (user) | mixed | TOML [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:
{
"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):
{
"mcpServers": {
"my-tool": { "command": "my-tool-bin" }
}
}.vscode/settings.json (two shapes supported):
{
// Flat format
"mcp.servers": {
"my-tool": { "command": "my-tool-bin" }
}
}{
// 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
{
"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:
{
"mcpServers": {
"my-tool": { "command": "my-tool-bin" }
}
}Agency TOML
[mcps.builtins.bluebird]
enabled = true
[mcps.builtins.raven]
enabled = falseEnabled builtins are spawned via agency mcp <name>.
Priority and Deduplication
When the same server name is found in multiple sources:
- Fleet config wins — servers in
~/.fleet/config.jsonalways take precedence over discovered ones - First source wins — among discovered servers, the first source to register a name keeps it
- 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():
| Scenario | Result |
|---|---|
| No active crew | Worker gets all fleet MCP servers |
Active crew, no mcpServers declared | Worker 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)
---
name: my-crew
mcpServers: [github, slack]
agents:
- role: coder
- role: reviewer
---Both coder and reviewer get access to github and slack.
Agent-level override
---
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:
// 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
- Check
~/.fleet/config.json— is the server listed undermcpServers? - Run
/mcp listto see configured servers - Run
/mcp statusto see active servers in the current session - Check if
mcpDiscovery.enabledis set tofalse - Check if the server is in
mcpDiscovery.excludeServers
Discovered servers not loading
- Ensure the config file exists in the expected location (see table above)
- Ensure the server entry has either
command(stdio) orurl(sse/http) - Check if another source already registered the same server name (first wins)
- Check the startup log for
🔌 Discovered MCPs:messages
Workers can't access MCP tools
- Check if a crew is active — crew MCP allowlisting may be restricting access
- If a crew is active but has no
mcpServersdeclared, workers get no MCP access - Add the server name to the crew or agent-level
mcpServerslist