CLI reference
Every finch command, grouped by what you do with it. finch runs on macOS and Linux. Run finch on its own for the list of commands, and finch help <command> (or finch <command> -h) for one command's usage, flags and an example.
Driving finch with an agent? Point it at
/agents.md, a step-by-step guide written for agents (the installed binary prints a copy with
finch guide). Every command below takes
--json, so the only step that needs you is approving the login. One paste does it: “Read https://finchmcp.com/agents.md and use finch to publish my MCP server on http://127.0.0.1:8000 as notes. Show me the sign-in link when you get it. Run it as a background service, check it with finch test, then connect it to this agent.”
By hand, start to finish
finch login # opens the sign-in page and waits
finch add notes --service http://127.0.0.1:8000 # prints the public URL
finch service install # keep it running in the background
finch test notes # does it answer through finch?
finch connect notes --client claude-code # add it to your MCP client
Set up
| Command | What it does |
|---|
finch login | Log this machine in to your account. Prints a link and a short code, opens the link in your browser and waits until you approve it. You can approve on any device, such as your phone. --headless skips the local browser (use it over SSH). --hub URL logs in to another finch hub. |
finch add <name> --service <url> | Publish the local app at <url> as <name>: add it to your account and to finch.yml, and print its public URL (JSON field url). The name becomes the URL segment, <account address>.finchmcp.com/<name>/, lowercased and with each run of other characters turned into - (My_API.v1 is published as my-api-v1; see names). Running it again for a name this machine already serves updates that service's local URL instead of adding a second service, and restarts the background service if it is running. |
--public | Let anyone with the URL in, with no key. Change it later with finch auth. |
--forward-all | Forward every path under /<name>/ to the app, for a web app or REST API. Without it finch forwards only /<name>/mcp. See Web apps and REST APIs. |
finch service install | Run finch in the background: it starts at login and restarts if it exits. A launchd LaunchAgent (~/Library/LaunchAgents/com.finchmcp.finch.plist) on macOS, a systemd user unit (finch.service) on Linux. Safe to run again, and running it again is how you apply changes to finch.yml. It waits for every service to connect and exits 1 if finch does not come up or a service has not connected within about 20 seconds; the unit stays installed and the message says why. On a headless Linux machine, sudo loginctl enable-linger $USER keeps it running after you log out. |
finch service status / uninstall | Say whether the background service is installed and running, or stop and remove it. uninstall exits 1 and keeps the unit if finch could not be stopped. |
finch run [--config finch.yml] | Serve every service in finch.yml in the foreground, until you press Ctrl-C. |
Log in from a script or agent
Plain finch login waits for you and has no --json form. Scripts and agents split it in two, so they can show you the link and keep working:
| Command | What it does |
|---|
finch login --start | Start a login and return at once. Prints the sign-in link and code (JSON: user_code, verification_uri_complete, expires_in, interval) and saves the pending login to ~/.finch/login-pending.json (mode 0600). |
finch login --poll | Check the pending login once. Exit 0 when approved, 10 while it waits, 11 once the code has expired. JSON: {"status":"approved"|"pending"|"expired"}. Until it resolves, every other command reports APPROVAL_PENDING, even when an older login is saved. |
finch login --cancel | Drop a login started with --start. The saved login, if any, works again. JSON: {"cancelled":true|false}. |
finch login --token - | Log in with a token from finch token, read from stdin (or set FINCH_CLI_TOKEN). A token passed as an argument works but warns: it lands in the process list and shell history. |
Connect a client
| Command | What it does |
|---|
finch connect <name> --client claude-code | Makes a finch_ key scoped to the service, saves it to ~/.finch/connect/<name>.claude-code.json (mode 0600), and adds the server to the current directory's Claude Code project with claude mcp add-json. The entry's headersHelper reads the key from that file, so the key never appears in a command line. Claude Code runs the helper only in a trusted workspace. Needs the claude CLI on PATH. |
finch connect <name> --client cursor | Makes a key and adds the server to ~/.cursor/mcp.json, keeping every other entry. |
finch connect <name> --client codex | Makes a key and writes [mcp_servers.<name>] into ~/.codex/config.toml, keeping the rest of the file. |
finch connect <name> --client json | Makes a key and prints an mcpServers JSON snippet for any other client. This is the only mode that prints the key. |
Each connect makes its own key, labelled with the client and machine, so you can revoke one client with finch keys revoke <id> without touching the others. The client is checked before a key is made, and a key whose setup fails is revoked again. A public service gets no key. Running connect again for Claude Code, Cursor or Codex replaces the entry and revokes the key the old entry used (listed as revoked_key_ids in --json), so re-running it rotates the key. Every Claude Code project on the machine connected to the same service shares the one key file, so they all move to the new key.
See what's happening
| Command | What it does |
|---|
finch status | This machine at a glance: whether you are logged in (logged_in; loggedIn is kept for older scripts) or a login is waiting for approval (login_pending), which services its finch.yml serves and their public URLs (url, when logged in and finch answers), and whether the background service is installed and running. It always exits 0; read the fields. |
finch fleet | Every service on your account, with its state (online, offline, pending) and public URL (url). Alias: finch ls. |
finch logs <name> | Recent calls to a service: time, route, caller, status and duration. --limit N sets how many. This is the whole call record finch keeps; request and response bodies are never stored (see Privacy). |
finch version | The installed version and platform. |
finch guide | Print the step-by-step guide for agents. |
Test a service
| Command | What it does |
|---|
finch test <name> | Open an MCP session with the service through finch and list its tools. Exits non-zero when that fails, and the message says which part failed. If your server refuses the session with HTTP 406, or a 400 that mentions the session, it starts with “the server rejected the MCP handshake” and quotes the answer. Other refusals name the status or the error, as “<name> answered tools/list with HTTP <status>” or “<name> answered tools/list with an MCP error” followed by the answer, even when it was the opening handshake your server refused. A 401 says your MCP server asks for its own credentials, and a 5xx reads “<name> did not answer through finch”. |
finch call <name> <tool> [--args '{...}'] | Call one MCP tool through finch. --args takes a JSON object. A tool that reports an error exits 1. |
finch test notes
notes — 2 tool(s):
• search Search notes
• read Read one note
finch call notes search --args '{"q":"finch"}'
Keys and tokens
| Command | What it does |
|---|
finch keys mint <label> --service <name> | Make a finch_ key for a client, scoped to one service. The key prints once. --all scopes it to every service instead. |
finch keys list | List client keys (id and label). |
finch keys revoke <id> | Revoke a client key. Access stops immediately. |
finch token [--login] | Make a fresh login token on a logged-in machine, to set up another machine without a browser. --login prints a ready-to-run finch login command that feeds the token on stdin. |
finch revoke-tokens | Log out every machine, including the one you run it on. |
Two kinds of credentials. The login token (about 30 days) is what a machine uses to manage your account: add services, make keys, revoke access.
finch_ keys are what clients present to reach your services. See
Keys & auth.
Manage
| Command | What it does |
|---|
finch auth <name> public|key | Choose whether callers need a finch_ key (or OAuth sign-in). public lets anyone in. |
finch rm <name> | Remove a service: from your account, from this machine's finch.yml, and its credential on this machine. |
finch update [--force] | Update finch to the latest version and restart the background service on it. When you already have the latest it says so (“finch 1.8.0 is already the latest”) and downloads nothing; --force reinstalls anyway. --restart auto|service|self|none controls the restart. |
finch domain ls | List custom hostnames on your account; finch domain add <hostname> and finch domain rm <hostname> manage them. Custom hostnames don't serve traffic yet; see Domains. |
Remove finch
finch uninstall
finch uninstall takes finch off this machine and prints each step as it goes. It:
- stops and removes the background service;
- revokes the keys this machine made with
finch connect, and removes the client entries finch added to Claude Code, Cursor and Codex. A machine set up before finch 1.8 kept no record of its keys, so there it revokes none and lists the keys that carry this machine's name for you to check; logged out or offline, it revokes none and says so; - deletes this machine's login, service credentials and
finch.yml from ~/.finch/.
It never deletes the finch binary itself; it prints the command that does. Your account and services stay; finch rm <name> removes a service, and finch revoke-tokens logs out every other machine. With --json it reports each step.
Less common
| Command | What it does |
|---|
finch enroll <name> --ticket - | On a machine with no login: trade a one-time ticket (stdin, or FINCH_TICKET) for a credential that serves one service. A logged-in machine uses finch add instead. |
finch approve <name> | Approve a service that a machine enrolled with a ticket, which waits as pending until you do. Run it from a logged-in machine. Services you add with finch add never need it. |
JSON output and exit codes
Every command takes --json. Success payloads go to stdout and carry "schema_version":1. Lists are wrapped in an object: finch fleet --json prints {"schema_version":1,"services":[…]}. Field names are snake_case. Errors go to stderr as one line:
{"schema_version":1,"error":{"code":"NOT_LOGGED_IN","message":"not logged in","next":"finch login --start"}}
When next is present, it is the command to run next. Exit codes are the same everywhere:
| Exit | Meaning | Error codes |
|---|
0 | OK | |
1 | Error | NOT_FOUND, UPSTREAM (finch or your server failed), INTERNAL (a local problem) |
2 | Usage: the command line was wrong | USAGE |
10 | Waiting for login approval | APPROVAL_PENDING |
11 | The login code expired | EXPIRED |
12 | Not logged in, or the login was revoked | NOT_LOGGED_IN |
finch status --json
{"schema_version":1,"account":"you@example.com","config":"/Users/you/.finch/finch.yml",
"hub":"https://finchmcp.com","hub_reachable":true,
"ingress":[{"app_path":"notes","service":"http://127.0.0.1:8000",
"url":"https://sunny-wren-42.finchmcp.com/notes/mcp"}],
"loggedIn":true,"logged_in":true,"login_pending":false,
"service":{"installed":true,"manager":"launchd","running":true,…},
"version":"1.8.0",…}
finch.yml
finch add writes this file (at ~/.finch/finch.yml unless the current directory has a finch.yml). It holds no secrets; credentials are saved separately under ~/.finch/.
hub: https://finchmcp.com
box: studio # this machine's name
ingress:
- app_path: notes # the service name: sunny-wren-42.finchmcp.com/notes/
service: http://127.0.0.1:8000
- app_path: demo
service: http://127.0.0.1:3000
forward_all: true # set by --forward-all