Run your own finch
Everything behind finchmcp.com is in the open-source repository: the hub, this website and the CLI. This guide deploys the hub and website on your own Cloudflare account, with your own Clerk sign-in, and points the finch CLI at them.
https://finch.example.dev/<service>/mcp. The layout finchmcp.com uses, where each account gets its own subdomain, is tied to the finchmcp.com name in the code today. The changes needed to run it on another domain are listed in the coupling checklist. This single-account mode is how finch's own staging deployment runs.What you deploy
| Piece | What it does |
|---|---|
| Hub | A Cloudflare Worker with three Durable Objects. It relays calls, checks keys, serves the CLI's API and the /install script. Source: worker/. |
| Website | A Cloudflare Worker running Next.js. Sign-in and the finch login approval page, plus the landing page and docs. Source: web/. |
| Clerk | Your sign-in, and the OAuth server for MCP clients that sign in instead of using a key. |
| Release binaries | What /install and finch update download: this repository's GitHub releases, or an R2 bucket you fill. |
Before you start
- A Cloudflare account. finchmcp.com runs on Workers Paid; the free plan's daily request limits are low for a relay.
- A Clerk account, Node 22, and
npx wrangler logindone once. - Two hostnames: one for the hub (
finch.example.dev) and one for the website (example.dev). Workers Custom Domains create the DNS records and certificates, so no wildcard DNS is needed. Yourworkers.devsubdomain works too. - The repository, checked out at a release tag so the hub matches the published binaries. This guide is written for
v1.8.0; a newer tag works the same way ifRELEASES_BASEnames that tag too:
git clone https://github.com/DigiBugCat/finch && cd finch
git checkout v1.8.01. Set up Clerk
- Create an application. A development instance is simplest for one person: it works on any origin. A production instance needs DNS on your domain; see the Clerk note under Known limitations.
- Restrict sign-ups to your email, or turn them off once your user exists. This step is required: development instances accept anyone by default, and a stranger who can sign in can log a CLI in to your hub, register your hub's own hostname to their account with
finch domain add, and receive every call made to it. TheVANITY_SUFFIXESandVANITY_TENANTsettings below close the same hole in the hub. Do both. - Create your user and copy its ID (
user_…). It becomes your finch account ID. - For MCP clients that sign in with OAuth (such as claude.ai custom connectors), open OAuth applications, turn on dynamic client registration, and set the default scopes for dynamically registered clients to
openid email profile. - Note the publishable key, the secret key, and the Frontend API URL.
2. Deploy the hub
Add a selfhost environment to worker/wrangler.jsonc. The full block, with every binding and migration it must repeat, is in the self-hosting guide on GitHub. The settings that are yours:
| Setting | What it does |
|---|---|
DEV = "1" | Turns on single-account mode. Keys, OAuth and machine tokens are checked exactly as in production. |
DEFAULT_TENANT | Your Clerk user ID. Every call on the hub host belongs to this account. |
WEB_URL | Your website origin. finch login sends you to <WEB_URL>/cli. |
CLERK_ISSUER | Clerk's Frontend API URL. Turns on OAuth sign-in for MCP clients. |
VANITY_SUFFIXES | Your hub hostname (finch.example.dev). Required on your own domain: with VANITY_TENANT, only your account can register it, so no one else can take over the hub. Not needed on workers.dev. |
VANITY_TENANT | Your Clerk user ID, the same value as DEFAULT_TENANT. |
FINCH_SERVICE_SECRET (secret) | Shared with the website; authenticates its calls and signs CLI tokens. It is a hub-wide credential: whoever holds it can act for any account on the hub. |
TICKET_SECRET (secret) | Signs the tokens your machines use to connect. |
FINCH_ASSERTION_PRIVATE_JWKS (secret, required by the guide's block) | Signs X-Finch-Assertion, the caller identity your services can verify. The guide's block sets FINCH_ASSERTION_ACTIVE_KID and FINCH_ASSERTION_ISSUER, which turn signing on; without this secret every authenticated call fails with 503. To run without assertions, remove those two and skip this secret. |
RELEASES_BASE or an R2 RELEASES bucket | Where binaries come from. Point RELEASES_BASE at https://github.com/DigiBugCat/finch/releases/download/v1.8.0 to use this repository's release. |
Set the secrets with fresh values and deploy. The assertion key's kid (selfhost-2026-09 here) must match FINCH_ASSERTION_ACTIVE_KID:
cd worker && npm ci
SERVICE_SECRET="$(openssl rand -hex 32)"
printf %s "$SERVICE_SECRET" | npx wrangler secret put FINCH_SERVICE_SECRET --env selfhost
openssl rand -hex 32 | npx wrangler secret put TICKET_SECRET --env selfhost
node scripts/generate-assertion-jwks.mjs selfhost-2026-09 \
| node scripts/validate-assertion-jwks.mjs selfhost-2026-09 --passthrough \
| npx wrangler secret put FINCH_ASSERTION_PRIVATE_JWKS --env selfhost
node scripts/deploy-preflight.mjs selfhost
npx wrangler deploy --env selfhostThe website needs the same FINCH_SERVICE_SECRET, so deploy it from the same shell or keep the value somewhere safe.
3. Deploy the website
Add the matching selfhost environment to web/wrangler.jsonc (again, the full block is in the guide): a FINCH_HUB service binding to your hub Worker, HUB_URL set to your hub's origin, NEXT_PUBLIC_APP_ORIGIN set to your website's exact origin, and your Clerk publishable key. Deploy the hub first, so the binding has something to point at.
cd ../web && npm ci
npx wrangler secret put CLERK_SECRET_KEY --env selfhost
printf %s "$SERVICE_SECRET" | npx wrangler secret put FINCH_SERVICE_SECRET --env selfhost
node scripts/deploy-preflight.mjs selfhost
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_... npx opennextjs-cloudflare build --env selfhost
npx opennextjs-cloudflare deploy -- --env selfhost4. Point the CLI at your hub
curl -fsSL https://finch.example.dev/install | sh
finch login --hub https://finch.example.devSign in on your website and approve the code. The CLI remembers the hub, so the rest of the usual flow needs no --hub:
finch add notes --service http://127.0.0.1:8000
finch service install
finch test notes
finch connect notes --client claude-code5. Check that it works
| Run | Expect |
|---|---|
curl https://finch.example.dev/api/version | The version you deployed |
finch add hello --service http://127.0.0.1:8000 | Prints https://finch.example.dev/hello/mcp |
finch test hello | Lists the server's tools |
curl -i https://finch.example.dev/hello/mcp | 401 with a WWW-Authenticate: Bearer challenge |
curl https://finch.example.dev/.well-known/oauth-protected-resource/hello/mcp | authorization_servers is your Clerk Frontend API URL |
Known limitations
These come from an audit of every finchmcp.com reference in the code. The coupling checklist lists the change that would remove each one.
- One account per hub. Per-account subdomains on your own domain need code changes in the hub.
- The website's content names finchmcp.com. The landing page, these docs,
/agents.mdand/llms.txtsend visitors and agents to finchmcp.com until you edit them. - Clerk production keys pin sign-in redirects to finchmcp.com (
web/app/layout.tsx). Use a development instance, or change that line in your copy. - The installer's closing hints assume finchmcp.com, and the CLI falls back to it when it has no saved hub. Pass
--hubor setFINCH_HUB.finch updateandfinch enrollignoreFINCH_HUB: on a machine with no saved login, pass them--hub. - Binaries come from this repository unless you build and publish your own.
- The deploy tooling is written for finchmcp.com. Use your own environment name, as above, rather than editing
production.
Updating is the same steps from a newer tag: deploy the hub, then the website, then run finch update on each machine (with --hub where there is no saved login). The full guide, with every configuration block, is docs/self-host.md.