Skip to content

CLI Commands

mcpfleet [command] [flags]

Run mcpfleet <command> --help for the same information in your terminal.

Flag Description
-h, --help Show help for any command
-v, --verbose Print debug logs to stderr (for example, which registry apply uses and which config file it writes). Without it, commands print only warnings and errors to stderr; results go to stdout
--version Print the version, commit and build date, e.g. mcpfleet version 0.1.0 (commit abc1234, built 2026-11-05T10:00:00Z)

Every command that talks to the registry (list, apply, push, pull, delete) needs a stored token and a registry URL.

What Where it comes from
Registry URL 1. MCPFLEET_REGISTRY_URL environment variable
2. ~/.config/mcpfleet/registry_url (written by auth login --url)
3. Default: https://registry.mcpfleet.dev
Auth token ~/.config/mcpfleet/token (written by auth login, file mode 0600)
Secrets for env and headers values ~/.config/mcpfleet/vault.enc, encrypted with a key kept in the OS keyring

No public registry answers at the default URL yet: point mcpfleet at your own registry (see Self-Hosting the Registry) with auth login --url or MCPFLEET_REGISTRY_URL. When nothing answers at the default URL, commands that talk to the registry fail with registry: request failed: … — no registry answers at the default URL https://registry.mcpfleet.dev; point mcpfleet at your registry with 'mcpfleet auth login --url <registry>' or MCPFLEET_REGISTRY_URL.

A trailing / on the registry URL is ignored. Without a stored token list, push, pull and delete fail with Error: registry client: registry: not authenticated — run 'mcpfleet auth login' first, and apply fails with Error: registry: not authenticated — run 'mcpfleet auth login' first.


Without a subcommand, mcpfleet opens a terminal UI with three tabs:

  • Dashboard: the number of servers in the registry and of supported agents
  • Servers: the servers stored in the registry
  • Adapters: every supported agent and the config file mcpfleet writes for it

Keys: tab switches tabs, 1–3 jump to a tab, q or ctrl+c quits.

The tabs stay empty until you log in with mcpfleet auth login.


Store the registry URL and the auth token.

Terminal window
mcpfleet auth login [--url <registry-url>] [--token <token>]
Flag Description
--url <url> Registry URL, saved to ~/.config/mcpfleet/registry_url for later commands
--token <token> Auth token for non-interactive use (scripts, CI)

Without --token, an interactive form asks for the registry URL and the token. With --token, no form is shown.

  • The URL must be an absolute http:// or https:// URL with a host. An invalid URL fails before anything is saved.
  • An empty URL keeps the previously saved one (or the default).
  • MCPFLEET_REGISTRY_URL, when set, still wins over the saved URL.
  • Login does not contact the registry. A wrong token shows up on the next command as registry: token invalid or expired.
Terminal window
# Interactive
mcpfleet auth login
# Non-interactive (self-hosted registry)
mcpfleet auth login --url http://localhost:8080 --token mcp_0123abcd...

Delete the stored token. The saved registry URL stays. Prints Not logged in. when there is no token.

Terminal window
mcpfleet auth logout

Show whether a token is stored, with the token masked, and the registry URL later commands use, with where it came from: MCPFLEET_REGISTRY_URL, ~/.config/mcpfleet/registry_url or default (see Registry and credentials). The Registry: line is printed also when you are not logged in. This command only reads local files and environment and does not contact the registry.

Terminal window
mcpfleet auth status
✓ Logged in (token: mcp_************beae)
Registry: https://registry.example.com (from MCPFLEET_REGISTRY_URL)
Not logged in.
Registry: https://registry.mcpfleet.dev (from default)

List all MCP servers in the registry. Alias: ls.

Terminal window
mcpfleet list [--json]
Flag Description
--json Print the servers as a JSON array instead of the table
MCP Servers
NAME TRANSPORT TARGET
---- --------- ------
filesystem stdio npx -y @modelcontextprotocol/server-filesystem '/home/me/My Projects'
github stdio npx -y @modelcontextprotocol/server-github
remote-api http https://example.com/mcp

TRANSPORT is stdio, http or sse; a server stored without a transport shows as stdio. TARGET is the command with its arguments for a stdio server and the url for an http or sse server. A server with no command or URL shows -.

The command and each argument in TARGET are quoted like words in a POSIX shell, so an argument with a space reads as one argument: /home/me/My Projects shows as '/home/me/My Projects', an empty argument as '', and it's as 'it'\''s'. A word that holds only letters, digits and @ % + = : , . / _ - is printed as is. Characters such as $ and ~ are quoted too, because the agent passes arguments literally, without expanding them.

An empty registry prints No servers registered.

With --json, list prints a JSON array with one object per server, using the same keys as a file for push — push reads JSON as well as YAML, so the output works as a backup you can push back:

Terminal window
mcpfleet list --json > servers.json
mcpfleet push servers.json
[
{
"name": "github",
"description": "GitHub MCP server",
"transport": "stdio",
"install": {
"type": "npx",
"package": "@modelcontextprotocol/server-github"
},
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-github"
],
"env": {
"GITHUB_TOKEN": {
"secret": "github_token"
}
},
"tags": [
"dev"
]
},
{
"name": "remote-api",
"transport": "http",
"install": {
"type": "",
"package": ""
},
"command": "",
"url": "https://example.com/mcp",
"headers": {
"Authorization": {
"secret": "example_auth"
}
}
}
]
  • Secrets appear only as references ({"secret": "<name>"}), never as values: list does not read your local vault. Literal values stored in the registry ({"value": "…"}) are printed as stored.
  • The registry’s id, created_at and updated_at fields are not included.
  • An empty registry prints [], with no header or message, so scripts can always parse the output.
  • Characters such as & in URLs are printed as is, not escaped.

For example, to print the names of the servers tagged dev with jq:

Terminal window
mcpfleet list --json | jq -r '.[] | select(.tags // [] | index("dev")) | .name'

filesystem stdio npx -y @modelcontextprotocol/server-filesystem /home/me/projects github stdio npx -y @modelcontextprotocol/server-github remote-api http https://example.com/mcp

`TRANSPORT` is `stdio`, `http` or `sse`; a server stored without a transport shows as `stdio`. `TARGET` is the command with its arguments for a `stdio` server and the `url` for an `http` or `sse` server. A server with no command or URL shows `-`.
An empty registry prints `No servers registered.`
---
## `mcpfleet apply`
Write the registry's server definitions into one agent's config file.
```bash
mcpfleet apply <agent> [--tag <tag>]...

<agent> is exactly one of: claude-code, claude-desktop, crush, cursor, windsurf, zed. See Agents for the file each one writes and how the merge works.

Flag Description
--tag <tag> Apply only servers that have this tag. Repeat the flag (or pass a comma-separated list) to apply servers that have any of the tags. Without --tag, all servers are applied

Before writing, env entries of a local server and headers entries of a remote server that reference a secret ({"secret": "<name>"}) are replaced by the value stored under that name in the local vault (store it with mcpfleet secret set). If a referenced secret is not in the vault, apply stops with an error that names every missing secret, with its server and variable or header, and writes nothing:

Error: missing secrets in vault: github_token (server github, env GITHUB_TOKEN), example_auth (server remote-api, header Authorization); set them with: mcpfleet secret set <name>

The env of a remote server is not written to any agent, so its secrets are not read.

If the vault cannot be opened (for example the OS keyring is locked), apply also stops before writing and shows the vault error. The vault is opened only when an applied server references a secret, so apply without secret references never asks for the keyring.

Remote servers (transport: http or sse) are written in the format each agent reads. A server the agent’s config file cannot hold (an http or sse server for claude-desktop, an sse server for zed), or a remote server without a url, is skipped with a warning on stderr; the other servers are still written and the Applied count leaves the skipped ones out. A skipped server’s secrets are not read from the vault. See Remote servers.

warning: skipping linear: claude-desktop does not support http servers in its config file
Terminal window
mcpfleet apply cursor
mcpfleet apply --tag dev cursor
mcpfleet apply --tag dev --tag vcs claude-code
mcpfleet apply claude-desktop
✓ Applied 2 MCP server(s) to claude-code

Create or update servers in the registry from a YAML file.

Terminal window
mcpfleet push <file>

The file is a YAML list of servers (the same format pull writes):

- name: filesystem
description: Read and write files in ~/projects
command: npx
args: ["-y", "@modelcontextprotocol/server-filesystem", "/home/me/projects"]
tags: [dev]
- name: github
command: npx
args: ["-y", "@modelcontextprotocol/server-github"]
env:
GITHUB_TOKEN:
secret: github_token # resolved from the local vault on apply
LOG_LEVEL:
value: debug
tags: [dev, vcs]
- name: remote-api
description: Remote MCP server over HTTP
transport: http
url: https://example.com/mcp
headers:
Authorization:
secret: example_auth # the whole value, e.g. "Bearer <token>"
Field Description
name Unique server name (required)
description Free text
transport stdio, sse or http; the registry stores stdio when empty
install type (npx, uvx, docker, binary, go), package, version
command, args The command the agent starts; command is required for stdio and must be left out for sse and http
url Address of a remote server, an absolute http:// or https:// URL; required for sse and http, left out for stdio
env Map of variable name to {value: ...} or {secret: ...}
headers sse and http only: map of HTTP header name to {value: ...} or {secret: ...}. Authorization, Proxy-Authorization and Cookie need a secret (see header rules)
tags Labels used by apply --tag
platforms linux, darwin, windows

For each server, push looks the name up in the registry: an existing server is replaced as a whole (fields missing from the file are cleared), a new one is created.

created filesystem
updated github

The registry checks each server before storing it (transport rules, header rules). A server that breaks a rule stops the push with the field and the reason, e.g.:

Error: create server "remote-api": registry: validation failed: body.url: url is required for transport sse
Error: create server "remote-api": registry: validation failed: body.headers.Authorization: use {"secret": ...} for credential headers; the registry does not store secret values

Servers earlier in the file are already stored at that point; fix the file and run push again.


Write all servers from the registry to a YAML file. An existing file is overwritten.

Terminal window
mcpfleet pull <file>
pulled 2 server(s) -> servers.yaml

Secret references stay references: pull never writes secret values.


Remove a server from the registry by name. Alias: rm.

Terminal window
mcpfleet delete <name>
Server "github" removed from registry.

When no server has that name, delete fails with exit code 1:

Error: server "github" not found in registry

This needs a registry that answers 404 for an unknown server; an older registry answers 204, and delete then reports success. delete does not touch agent config files: remove the entry there by hand if you no longer want it.


Manage the secrets in the local vault (~/.config/mcpfleet/vault.enc, encrypted with AES-256-GCM, key in the OS keyring). Registry entries refer to them by name (env: GITHUB_TOKEN: {secret: github_token}), and apply fills in the values. Secrets never leave your machine.

Store a secret, or replace the value of an existing one.

Terminal window
mcpfleet secret set <name> [--stdin]
Flag Description
--stdin Read the value from standard input instead of the hidden prompt. One trailing newline (\n or \r\n) is dropped, everything else is kept

The value is never taken from an argument, so it does not end up in your shell history. Without --stdin, a prompt asks for the value and does not show what you type; when standard input is not a terminal, the command fails with stdin is not a terminal; pipe the value with --stdin. An empty value is rejected. The name can be any non-empty string without leading or trailing spaces; use the name the registry entry references.

Terminal window
mcpfleet secret set github_token
printf '%s' "$GITHUB_TOKEN" | mcpfleet secret set github_token --stdin
✓ Saved secret github_token

Replacing an existing secret prints ✓ Updated secret github_token.

Print the names of the stored secrets, one per line, sorted. Values are never printed.

Terminal window
mcpfleet secret list
github_token
slack_token

With no secrets stored, nothing goes to stdout and a hint goes to stderr.

Remove a secret from the vault.

Terminal window
mcpfleet secret rm <name>
✓ Removed secret github_token

A name that is not in the vault fails with secret "<name>" not found.


Generate a shell completion script (bash, zsh, fish or powershell).

Terminal window
mcpfleet completion zsh > "${fpath[1]}/_mcpfleet"

Errors go to stderr as Error: <message>, for example:

Error: unknown agent "nope" (supported: claude-code, claude-desktop, crush, cursor, windsurf, zed)
Code Meaning
0 Success
1 Any error