Skip to main content
Glama

appbyggaren-mcp

An MCP server that lets an agent publish small static web apps: source into Gitea, build and TLS via Coolify. Five verbs, hard boundaries.

Built to give a household assistant a "mini Lovable" — "build me a page that counts down to the summer holidays" — without giving it the keys to the PaaS.

Why it exists

Coolify's own MCP server is read-only, and its API tokens are instance-wide capabilities (read / write / deploy / root) with no per-project scoping. Handing that token to a model means handing it every application on the instance, including the ones you care about.

This server sits in between. It holds the write credentials; the model gets five verbs that cannot express anything outside the configured project, organisation and domain. The asymmetry is the whole design.

Related MCP server: mcp-gitea

Tools

Tool

Does

list_apps

Apps published by this server, with status and URL

get_app

Status, URL and repository for one app

create_app

Create repo, push files, create the Coolify app, deploy

update_app

Replace files and redeploy

get_deploy_logs

Last deployment log — for when a build fails

delete_app

Remove the app; keeps the repo unless asked otherwise

Apps are static sites served by nginx: HTML, CSS and client-side JS. No server-side runtime, no database.

Boundaries

Enforced in guards.py, on every mutating call:

  • Project — an application's project UUID is re-checked against the configured one before it can be touched. The UUID is the only thing the caller supplies, so it is never trusted.

  • Domain — publishing is limited to <name>.<APPBYGGAREN_DOMAIN_SUFFIX>. An app re-pointed elsewhere in the Coolify UI drops out of scope and becomes immutable here.

  • Organisation — repositories are only created under GITEA_ORG.

  • Names^[a-z0-9][a-z0-9-]{0,30}[a-z0-9]$, with a reserved list. The slug becomes a DNS label, a repo name and a container name, so it must survive all three.

  • Payload — max 40 files, 2 MB total, index.html required, and paths are normalised to reject traversal. Gitea's contents API takes the path verbatim, so ../ would otherwise escape the repository.

Configuration

All via environment variables — see .env.example. The Coolify, Gitea and domain settings are required; everything else is optional.

Nothing about a particular deployment is baked into the source. Which hostnames are already taken, which domains count as internal, and which names are worth flagging are all properties of your installation — hard-coding them here would publish your DNS layout to anyone reading the repository.

Variable

Effect when unset

APPBYGGAREN_RESERVED_NAMES

Only the generic baseline is reserved

APPBYGGAREN_INTERNAL_DOMAINS

The internal-hostname check does not run

APPBYGGAREN_PII_NAMES

No names are flagged

CLOUDFLARE_ACCESS_TOKEN + CLOUDFLARE_ACCOUNT_ID

publish_app refuses, with a message saying why

The content scan is a filter, not a judgement

publish_app refuses when it finds personal numbers, email addresses, phone numbers, private IPs, secrets, or anything you listed above. It will not notice that "countdown to our holiday, 14 July" says when a house will be empty. Read what the app actually says before publishing it.

Install

uv venv .venv && uv pip install --python .venv/bin/python .
.venv/bin/appbyggaren-mcp          # stdio transport

Register with an MCP client (example: Hermes Agent):

hermes mcp add appbyggaren --command /opt/appbyggaren-mcp/.venv/bin/appbyggaren-mcp

If your client passes no environment to stdio children, reference the variables as ${VAR} placeholders in its config rather than inlining secrets.

Known Coolify quirks

/applications/public truncates the git URL. It stores only owner/repo and leaves git_full_url, source_type and source_id null, assuming a hosted provider. A self-hosted Gitea URL then never clones — and the failure is silent: HTTP 201, no deployment recorded, no container, status exited:unhealthy, no error anywhere. This server issues a PATCH with the full .git URL immediately after creation and refuses to deploy if the stored value still looks truncated.

Certificates lag the deploy. Traefik requests the certificate when the router appears, so the first seconds after publishing serve TRAEFIK DEFAULT CERT. That is not a failure; it resolves on its own.

Development

uv pip install --python .venv/bin/python -e ".[dev]"
.venv/bin/pytest
.venv/bin/ruff check .

Licence

MIT

Install Server
A
license - permissive license
A
quality
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

View all related MCP servers

Related MCP Connectors

  • A MCP server built for developers enabling Git based project management with project and personal…

  • MCP server for AI agents to plan, verify, and deploy Cloudflare-native apps.

  • An MCP server for Arcjet - the runtime security platform that ships with your AI code.

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/kanylbullen/appbyggaren-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server