Freelancers and agencies building custom MCP connectors for several clients tend to hit the same wall: the tools are 80% identical (CRM lookups, ticket search, a couple of internal APIs), but each client needs their own credentials, their own domain, and their own access list. The fix is not one shared server with a client ID parameter bolted on. It is one template, deployed once per client, so isolation is structural instead of something your code has to remember to enforce.
Build the template once
Write the connector as a normal project: a denkops.json, your tool handlers, connector: true for hosted OAuth. Keep client-specific values out of the code entirely, referenced only by env var name:
{ "name": "acme-support", "slug": "acme-support", "runtime": "bun", "connector": true }The handlers, the tool schemas, the error handling, all of it lives in one git repository. That repository is your product. What changes per client is not the code, it is the deploy target.
Deploy once per client, each in its own slot
Clone the repo's config per client (a folder, a branch, or a small script that stamps out denkops.json files with a different slug) and deploy each one separately. Every deploy lands in its own project, its own always-on slot, with its own environment variables, its own optional custom domain, and its own OAuth access policy. Client A's API key is never in the same process, the same slot, or even the same access list as client B's.
npx @denkopsai/mcp deploy --project acme-support
npx @denkopsai/mcp deploy --project globex-supportPush a fix to the template, redeploy the client projects that need it, and each rollout is independent: you can ship the fix to one client today and the rest next week without touching a shared service that all of them depend on.
One dashboard, twenty projects
The part that actually saves the time is not the deploy, it is what happens after. All of a client's projects live in the same dashboard, so you get one place to check status, read logs, roll back a bad deploy, and see who has access, across every client, without SSHing into anything or juggling separate consoles per customer. A support ticket that says "client X's connector is erroring" turns into: open the dashboard, find the project, read the logs, done.
This is the same shape as running twenty small SaaS backends, because that is what it is. Each client gets a real, isolated, always-on service; you get a single control plane over all of them. See the full list of what a deploy gives you on capabilities.