---
title: "Deploying the MCP Server | DreamFactory Docs"
source: "https://docs.dreamfactory.com/AI/mcp-server-deployment"
canonical_url: "https://docs.dreamfactory.com/AI/mcp-server-deployment"
converted_at: "2026-06-26T20:59:04.236Z"
format: "markdown"
converted_by: "html-to-md-ai"
---
This guide covers installing and operating the MCP server on your DreamFactory host: the Node.js daemon, configuration, and running behind a reverse proxy.

- To create an MCP service in the admin interface, see [Creating an MCP Server Service](/AI/mcp-service-creation).

- For the available tools, request format, and required headers, see [MCP Server](/AI/mcp-server).

## Overview[​](#overview)

The MCP server runs in two parts on your DreamFactory host:

- **PHP routes** served by DreamFactory at `/mcp/{service}`

- **A Node.js daemon** that handles the MCP protocol layer (the PHP side forwards to it)

Clients connect to `https://<host>/mcp/{service}` — never directly to the daemon.

## Prerequisites[​](#prerequisites)

A working DreamFactory installation, plus the following **on the server**:

- **Node.js 20+ and npm** — required to build and run the daemon. On Ubuntu:

```
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -sudo apt-get install -y nodejsnode -v && npm -v
```

- The `dreamfactory/df-mcp-server` package (included in the commercial composer set).

Confirm the package and routes are present:

```
ls vendor/dreamfactory/df-mcp-serverphp artisan route:list | grep '/mcp/'
```

## The MCP daemon[​](#the-mcp-daemon)

The daemon lives under `vendor/dreamfactory/df-mcp-server/daemon/` and listens on `127.0.0.1:8006`.

Build it:

```
cd vendor/dreamfactory/df-mcp-server/daemonnpm installnpm run build
```

Run it via the shipped start script:

```
vendor/dreamfactory/df-mcp-server/scripts/start-daemon.sh
```

### Daemonizing for production[​](#daemonizing-for-production)

No systemd unit ships by default. Add one so the daemon starts on boot and restarts on crash — `/etc/systemd/system/df-mcp-daemon.service`:

```
[Unit]Description=DreamFactory MCP DaemonAfter=network.target[Service]Type=simpleUser=www-dataExecStart=/opt/dreamfactory/vendor/dreamfactory/df-mcp-server/scripts/start-daemon.shRestart=alwaysRestartSec=5StandardOutput=journalStandardError=journalEnvironment=NODE_ENV=production[Install]WantedBy=multi-user.target
```

```
sudo systemctl daemon-reloadsudo systemctl enable --now df-mcp-daemonsudo systemctl status df-mcp-daemon
```

### Viewing the daemon logs[​](#viewing-the-daemon-logs)

Because the unit sends output to the journal (`StandardOutput=journal`), read the daemon's logs with `journalctl`:

```
sudo journalctl -u df-mcp-daemon -f             # follow livesudo journalctl -u df-mcp-daemon -n 100         # last 100 linessudo journalctl -u df-mcp-daemon --since "15 min ago"
```

tipPoint `ExecStart` at the shipped `start-daemon.sh`, which runs the compiled `dist/server.js`. Don't point it at `tsx` — that's a dev-only dependency and is removed by a production `npm install --omit=dev`.

noteIn the Docker/compose stack, the daemon starts automatically when `ENABLE_MCP_DAEMON` is set, so no systemd unit is needed.

## Configuration[​](#configuration)

Set these in your DreamFactory `.env`:

VariableSet toNotes`APP_URL``https://df.example.com`The external URL clients use. Not `http://localhost`.`DF_FRONTEND_URL`*(optional)*Override only if the admin SPA is on a different host.`LOG_LEVEL``warning`Set to `debug` while troubleshooting OAuth, then revert.

warning`APP_URL` must be the **external HTTPS URL** clients reach. It drives the OAuth discovery and callback URLs as well as server-side session validation. If it is left as `http://localhost` (or any value clients can't reach), MCP authentication fails — typically as a login page that loops.

Verify the value actually in use:

```
php artisan tinker --execute="echo config('app.url');"
```

## Applying configuration changes[​](#applying-configuration-changes)

DreamFactory caches configuration, so editing `.env` alone is not enough:

```
php artisan config:clear            # required — .env is ignored while config is cachedphp artisan config:cache            # only if you run cached config in productionsudo systemctl restart php8.5-fpm   # use your PHP version; also clears OPcache
```

- **Don't** run `php artisan` as `root` — it creates root-owned cache files that PHP-FPM can't read, causing 500s. Run it as a normal user. If it already happened, reset ownership to your web-server user, e.g. `sudo chown -R www-data:www-data storage bootstrap/cache`.

- **Don't** rely on a PHP-FPM restart alone to apply `.env` changes — run `config:clear` first.

- Restart PHP-FPM after editing any vendor PHP file (OPcache won't pick it up otherwise).

## Running behind a reverse proxy[​](#running-behind-a-reverse-proxy)

When a proxy (AWS ALB, nginx, Cloudflare) terminates TLS and forwards traffic to DreamFactory, the one thing you must do is set `APP_URL` to the external HTTPS URL (see [Configuration](#configuration)). That is sufficient for most deployments.

After applying the change, confirm OAuth discovery advertises **https** URLs:

```
curl -s https://df.example.com/.well-known/oauth-authorization-server/mcp/<service> \  | jq -r '.issuer, .authorization_endpoint'
```

If those URLs come back as `https://…`, no further proxy configuration is needed.

### Only if discovery still shows `http://`[​](#only-if-discovery-still-shows-http)

This means the proxy's scheme isn't reaching PHP. Pass it through in your nginx site:

```
# in the http { } blockmap $http_x_forwarded_proto $fcgi_https { default off; https on; }# in server { } -> location ~ \.php$ { }fastcgi_param HTTPS $fcgi_https;
```

```
sudo nginx -t && sudo systemctl reload nginx
```

For correct behavior across the rest of DreamFactory behind a proxy (redirects, secure cookies, client IPs in logs), also trust the proxy in `app/Http/Middleware/TrustProxies.php`:

```
protected $proxies = '*';   // or your load balancer / subnet CIDRsprotected $headers =    Request::HEADER_X_FORWARDED_FOR  | Request::HEADER_X_FORWARDED_HOST |    Request::HEADER_X_FORWARDED_PORT | Request::HEADER_X_FORWARDED_PROTO;
```

## Connecting a client[​](#connecting-a-client)

After [creating an MCP service](/AI/mcp-service-creation), point your client at `https://<host>/mcp/{service}`:

- **No trailing slash** — a trailing slash breaks OAuth discovery.

- **Not** `/api/v2/...` — that is the REST API and returns `400 No session token or API Key`.

Example VS Code `mcp.json`:

```
{  "servers": {    "df-poc": { "type": "http", "url": "https://df.example.com/mcp/poc" }  }}
```

noteNative clients (VS Code, Cursor, Claude Desktop) receive the OAuth code on a rotating `http://127.0.0.1:<port>/` listener. If you see `redirect_uri is not registered for this client`, free up the client's preferred fixed port (VS Code uses `33418`) and reconnect.

For tool calls and the full list of required headers, see [MCP Server](/AI/mcp-server#required-headers).

## Troubleshooting[​](#troubleshooting)

Enable debug logging first — OAuth failures are otherwise silent. Set `LOG_LEVEL=debug`, run `config:clear`, then:

```
tail -f storage/logs/dreamfactory.logsudo tail -f /var/log/nginx/access.log | grep -E "oauth-callback|user/session"
```

SymptomFixLogin page loops or flickersSet `APP_URL` to the external HTTPS URL, `config:clear`, restart PHP-FPMDiscovery advertises `http://` URLsSet `APP_URL` + TrustProxies + nginx `HTTPS` param`400 No session token or API Key`Client URL points at `/api/v2/...` — use `/mcp/{service}``.well-known` returns 404Use the service-scoped path `/.well-known/oauth-authorization-server/mcp/{service}``redirect_uri is not registered`Rotating loopback port — free/reuse the client's fixed port and reconnect404 on all `/mcp/*`Confirm the package is installed, then `php artisan route:clear`Config change has no effectRun `config:clear` (not just a PHP-FPM restart); ensure cache files aren't root-owned

## See also[​](#see-also)

- [MCP Server](/AI/mcp-server) — protocol overview, tools, and request format

- [Creating an MCP Server Service](/AI/mcp-service-creation)

- [Custom Login Page for MCP](/AI/mcp-custom-login-page)