Lovable is nice. You describe a site, an agent writes it, you click publish. It also costs $25–50 a month for the tiers that are actually usable, the code lives on their side, and the agent only knows how to do one thing.
I already pay for Claude. I already have a VPS with Dokploy on it. The missing piece was a way for the agent to deploy, and gateways for that already exist — MetaMCP, IBM’s ContextForge, a few others. None of them gave me the combination I wanted: multiple runtimes, one container, an OAuth server of its own, and a UI I don’t mind looking at. So I wrote one.
The setup
- any $5 VPS. 1 GB of RAM is enough for the gateway, Dokploy itself wants 2 GB
- Dokploy, which I was already using
- Junctio, an MCP gateway I wrote, one container next to Dokploy
- the official
@dokploy/mcpserver, running inside Junctio as a stdio process - AI Agent: Claude (Desktop/Code), ChatGPT, Codex, Cursor, whatever you have
The client talks to one URL. Junctio runs the Dokploy MCP server, keeps the Dokploy API key, and exposes the tools over Streamable HTTP with OAuth.
# Schema
AI Agent App --OAuth--> Junctio --stdio--> @dokploy/mcp --> Dokploy API
(API key lives here)
What happens
The prompt is something like: “Build a landing page for X, push it to my GitHub, deploy it on Dokploy under x.example.com”. The agent writes the page, creates the app in Dokploy, points it at the repo, adds the domain and triggers the build. A few minutes end to end, most of it the Docker build.
Every tool call goes through the gateway and lands in the request log: method, tool, upstream, status, timing. Bodies are not stored: arguments and results can carry anything your agent touched, and a log full of that is a leak waiting to happen.
Why a gateway and not just npx @dokploy/mcp in the client
claude.ai has no stdio. Claude Desktop and Claude Code will happily spawn a local stdio server; claude.ai in the browser and ChatGPT connectors will not, and they can’t send an API key header either. A custom connector means a remote MCP server with a real OAuth authorization server behind it: RFC 8414 metadata, dynamic client registration, PKCE, a consent screen. Junctio has that built in. Add the connector URL, approve at the consent screen with the admin password, done. No Cloudflare Worker wrapper, no separate auth service.
~600 tools is too many. The official Dokploy MCP server exposes the whole API, upwards of 600 tools at the moment.. That’s a lot of context, and the agent picks the wrong application-* call half the time. In Junctio I put the server in a namespace and hid everything except about 20: create project, create application, set source, set domain, deploy, read logs. Plus a short instruction block on the namespace (“never delete, ask before creating databases”). The client only sees the small set.
The key stays on the server. With the stdio setup every client machine has the Dokploy API key in a mcp.json. With the gateway there is one key, in one place, encrypted at rest. Each client gets its own OAuth client or API key and I can revoke it from the UI.
Compose
services:
junctio:
image: ghcr.io/k2so-dev/junctio:latest
pull_policy: always
restart: unless-stopped
environment:
JUNCTIO_SECRET: ${JUNCTIO_SECRET:?set JUNCTIO_SECRET, e.g. openssl rand -hex 32}
JUNCTIO_BASE_URL: ${JUNCTIO_BASE_URL:?set JUNCTIO_BASE_URL, e.g. https://mcp.example.com}
JUNCTIO_TRUST_PROXY: "true"
JUNCTIO_ADMIN_TOKEN: ${JUNCTIO_ADMIN_TOKEN:-}
LOG_LEVEL: ${LOG_LEVEL:-info}
volumes:
- junctio-data:/data
- junctio-cache:/cache
tmpfs:
- /tmp
read_only: true
networks:
- dokploy-network
networks:
dokploy-network:
external: true
volumes:
junctio-data:
junctio-cache:
Add it in Dokploy as a Compose service with the Raw provider. No published ports: Dokploy routes through its own Traefik, so the service joins dokploy-network and gets its domain on the Domains tab, pointed at container port 3000 with Let’s Encrypt on. junctio-cache holds the npx and uvx package caches — throwaway, but without it every cold start is slow. Outside Dokploy, put Caddy in front instead; either way OAuth needs TLS, while an API-key endpoint works fine over plain http on localhost.
Then in the UI: add server > runtime npx (or bunx) > package @dokploy/mcp > env DOKPLOY_URL, DOKPLOY_API_KEY. Create a namespace, hide tools, create an endpoint with OAuth on. Paste the URL into your agent app as a custom connector.
Full walkthrough: https://junctio.pages.dev/use-cases/claude-ai-connector/
What this is not
It is not Lovable. No live preview, no visual editor, no “click this button and change its color”. You get a chat and a deploy. If you want to iterate on UI visually, this is worse.
It is also not safer by default. You are giving an agent write access to your deployment platform. I hid the destructive tools and the agent still once tried to redeploy the wrong app because two had similar names. Keep a namespace per project, keep the tool set small, read the logs. Junctio can also run a scheduled vulnerability check on the servers it launches through npx, bunx, node or uvx, which matters when you install packages from npm with one click. It’s off by default, it’s advisory data rather than analysis, and container images, custom commands and remote servers are marked “not audited” because the gateway can’t tell what’s inside them:
Cost
VPS $5 a month. Dokploy free. Junctio free, MIT. AI subscription I already had.
Memory: Junctio idles at about 60 MB. A running stdio server adds its own footprint, @dokploy/mcp is another 60 MB or so. Idle servers get stopped after a timeout and restarted on the next call, so most of the time you’re back at 60 MB. It’s TypeScript on Bun, not Go, and I’m fine with that. I can maintain it.
What else this unlocks
The same trick works with anything that has an OpenAPI spec: run an OpenAPI-to-MCP server inside the gateway, hide the tools you don’t want, write instructions for the rest, and the agent can manage your shop, your DNS, your VPN panel. The gateway also browses the public MCP registry, so adding the next server is a click:
Repo: https://github.com/k2so-dev/junctio
Docs: https://junctio.pages.dev/docs/






Top comments (2)
This is nowhere near as smooth as Lovable, I know. But wait until the database grows: with Lovable that's a Supabase bill on top of the seat. Here it's bumping the VPS one tier. The two numbers don't compare.
Trimming the 600 tools down to 20 is the part that actually saves this. When an agent has 600 deployment endpoints in its prompt, it spends tokens hallucinating parameters or picking similar routes, and any network blip triggers weird retries.
I keep a similar rule for local runner tools: never expose the raw management API to an agent loop. A narrow whitelist of idempotent endpoints keeps the model from guessing, and keeping the API key out of local mcp.json files is just basic hygiene.